Добро пожаловать в четвертую часть этой серии на Objective-C. До сих пор мы много смотрели на теорию, принципы и функциональность языка, чтобы получить хорошее представление о том, как он работает. Сегодня мы будем делать простой класс, похожий на пример автомобиля, который мы рассматривали в предыдущих частях этой серии. Наш класс рассмотрит детали автомобиля, что позволит нам получить и установить установленные значения. После сегодняшнего примера вы сможете создать свои собственные классы в Xcode и поиграть с ними.
Пока что мы получили отличные отзывы по электронной почте, в твиттере и комментариях. Приятно видеть, что так много людей интересуются этим предметом, и еще лучше видеть, что многие из вас сами пробуют его и задают несколько замечательных вопросов. Так держать!
Начиная
Начните с запуска Xcode и создания нового проекта. Под разделителем Mac OS X нажмите «Приложение», затем «Инструмент командной строки». Наконец, измените раскрывающийся список, чтобы задать тип Foundation.
Сохраните проект как хотите, я назвал мой CarApp. Когда появится окно проекта, нам нужно создать новый класс. Нажмите Command-N (или «Файл»> «Новый файл»), перейдите к классу какао в Mac OS X и выберите класс Objective-C. Убедитесь, что для Subclass of установлено значение NSObject и нажмите Next. Назовите свой класс SimpleCar и убедитесь, что файл .h будет создан, а затем сохраните его.
Наш класс сейчас существует, но он ничего не делает. Давайте изменим это, дав код. Помните, что в Objective-C мы разделяем наш код на две части: интерфейс и реализация. Логично сначала поработать над интерфейсом, поэтому мы и начнем.
Кодирование интерфейса
Откройте файл SimpleCar.h и в его текущем состоянии он должен выглядеть следующим образом (я опустил заголовок комментария снизу)
#import <Cocoa / Cocoa.h> @interface SimpleCar: NSObject { } @конец
Прежде всего, мы включаем Cocoa.h, который дает нам доступ к таким вещам, как NSString, NSMutableString и т. Д. Затем мы создаем наш класс (SimpleCar) как подкласс NSObject.
Теперь нам нужно решить, какую информацию должен хранить наш класс. Поскольку в качестве примера мы используем автомобиль, нам необходимо хранить информацию, связанную с автомобилем, например:
- Сделать
- модель
- VIN
Мы могли бы заняться гораздо большим, но сейчас это подойдет. Для каждого из этих свойств нам нужно хранить их в переменной, подходящей для этого типа данных. Марка и модель будут представлять собой диапазон символов (например, текст, число и, возможно, знаки препинания), поэтому имеет смысл использовать строку. VIN (идентификационный номер транспортного средства) будет только числом, поэтому мы будем его использовать. Наш код теперь выглядит так (заголовок опущен):
@interface SimpleCar: NSObject { NSString * make; NSString * модель; NSNumber * vin; } @конец
Ранее мы говорили, что для получения или установки данных из класса следует использовать метод. Итак, чтобы установить переменные, нам нужно добавить методы. Чтобы сделать это, мы сделаем четыре: один установит make, один — модель, один VIN, и последний метод установит оба make и модель (просто чтобы показать вам, как использовать несколько аргументов).
@interface SimpleCar: NSObject { NSString * make; NSString * модель; NSNumber * vin; } // установить методы - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) setModel; // удобный метод - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @конец
Мы объявляем методы после фигурной скобки и перед @end. Помещая черту (знак минус) перед методом, мы сообщаем компилятору, что мы собираемся объявить метод экземпляра. Метод экземпляра — это метод, выполняемый в нашем экземпляре. И наоборот, знак плюс указывает, что вызываемый метод является методом класса, которому не требуется отдельный экземпляр объекта для выполнения -подробнее об этом позже.
Наш первый метод возвращает void, он называется setVin и принимает в качестве аргумента NSNumber. Наш второй метод похож, он возвращает void, вызывает setMake и принимает NSString в качестве аргумента. Третий такой же, с другим именем.
Наш последний метод также возвращает void, но принимает два параметра: newMake и newModel, оба из которых должны быть NSString. Именование, используемое в этом методе, аналогично названию большинства методов Objective-C: простым английским языком. Таким образом, когда вы читаете метод, разрешенный, становится очевидным, что метод будет «Установить марку и модель». Важно помнить, что имя метода в этом случае ‘setMake: andModel:’ — все названия аргументов включены в имя метода.
Важным примечанием является то, что мы используем (void), потому что наши методы не должны ничего возвращать. Так как все, что они делают, это устанавливают данные и не должны возвращать что-либо обратно (например, сообщение об успехе), мы просто используем void.
Далее мы добавим методы, которые будем использовать для получения значений. Хотя мы вызываем наши методы get и set, мы обычно используем только «set» в заголовке и опускаем «get». Как вы называете свои методы, в конечном счете, зависит от вас, но отбрасывание «get» является обычным делом и помогает избежать путаницы.
Наш новый набор методов выглядит следующим образом:
// установить методы - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // удобный метод - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // получить методы - (NSString *) сделать; - (NSString *) модель; - (NSNumber *) vin;
Обратите внимание, что методы get используют те же имена, что и переменные в классе. Это упростит процесс извлечения переменных. Это будет, как если бы мы обращались к переменным напрямую, по существу, делая методы get прозрачными.
Кодирование реализации
Итак, теперь, когда интерфейс на месте и мы знаем, что будет делать класс, нам нужно реализовать наши методы. Оглядываясь назад, мы должны реализовать четыре метода: setVin, setMake, setModel и setMake: andModel. Прежде чем перемещать файлы, скопируйте объявления методов в буфер обмена (Cmd + C). Теперь закройте SimpleCar.h и запустите SimpleCar.m в редакторе, вставив объявления методов между @implementation и @end, вот так:
@implementation SimpleCar // установить методы - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // удобный метод - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // получить методы - (NSString *) сделать; - (NSString *) модель; - (NSNumber *) vin; @конец
Очевидно, что это неправильно, поэтому нам нужно поменять точки с запятой на фигурные скобки, куда пойдет внутренняя работа метода, вот так:
@implementation SimpleCar // установить методы - (void) setVin: (NSNumber *) newVin { } - (void) setMake: (NSString *) newMake { } - (void) setModel: (NSString *) newModel { } - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel { } // получить методы - (NSString *) make { } - (NSString *) модель { } - (NSNumber *) vin { } @конец
Теперь нам нужно дать нашим методам некоторый код. Давайте начнем с методов получения, поскольку они достаточно просты. Для каждого метода получения все, что нам нужно, это убедиться, что функция возвращает то, что она должна вернуть. По этой причине наши методы получения выглядят так:
- (NSString *) make { возврат сделать; } - (NSString *) модель { возвращаемая модель; } - (NSNumber *) vin { вернуть вин; }
Помните : методы возвращают переменные, которые мы определили в файле интерфейса. Не путайте имена методов и переменных.
Это довольно просто, когда мы вызываем make (например), а затем make возвращает указатель на NSString — в данном случае на переменную make. То же самое происходит для модели и vin (за исключением, конечно, vin возвращает число).
Теперь для методов установки, сначала мы посмотрим на код, а затем пройдемся по нему позже. Наши методы установки выглядят так:
// установить методы - (void) setVin: (NSNumber *) newVin { [Вин релиз]; vin = [[NSNumber alloc] init]; vin = newVin; } - (void) setMake: (NSString *) newMake { [сделать релиз]; make = [[NSString alloc] initWithString: newMake]; } - (void) setModel: (NSString *) newModel { [выпуск модели]; модель = [[NSString alloc] initWithString: newModel]; } // удобный метод - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel { // Используйте наши методы ранее [self setMake: newMake]; [self setModel: newModel]; }
Методы set немного сложнее, чем наши методы get. Мы хотим распределить значения, которые передаются в каждый метод, чтобы они принадлежали классу. Сначала мы выпускаем эти переменные, если они уже выделены. Если они не распределены, то они равны нулю, а объекты с нулем игнорируют передаваемые им сообщения. Мы рассмотрим эти вопросы подробнее, когда будем обсуждать управление памятью.
Поскольку мы фактически выделяли память для наших объектов в методах установки, мы должны быть уверены, что освободим их, когда объект будет освобожден из памяти. Для этого нам нужно добавить собственный метод dealloc, например так:
- (недействительно) dealloc { [Вин релиз]; [сделать релиз]; [выпуск модели]; [супер сделка]; }
Тестирование класса
Поздравляем! Если вы выполнили все вышеперечисленное, то теперь у вас должен быть рабочий класс (если нет, загрузите исходные файлы, доступные в этой статье). Итак, давайте проверим это.
Откройте основной файл вашего проекта (мой называется CarApp.m), который по умолчанию должен выглядеть примерно так:
#import <Foundation / Foundation.h> int main (int argc, const char * argv []) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Вставить пользовательский код здесь ... NSLog (@ "Привет, мир!"); [сток бассейна]; вернуть 0; }
Удалите комментарий и строку NSLog, так как они нам сейчас не понадобятся.
Чтобы начать использовать наш класс, нам нужно включить его в программу. Под исходной строкой #import добавьте следующую строку:
#import "SimpleCar.h"
Наш класс теперь доступен для использования, но нам нужно создать его экземпляр, чтобы протестировать его. Вот код, используемый в целом:
#import <Foundation / Foundation.h> #import "SimpleCar.h" int main (int argc, const char * argv []) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; SimpleCar * myCar = [[SimpleCar alloc] init]; NSNumber * newVin = [NSNumber numberWithInt: 123]; [myCar setVin: newVin]; [myCar setMake: @ "Honda" andModel: @ "Civic"]; NSLog (@ "Автомобиль:% @% @", [myCar make], [myCar model]); NSLog (@ "The vin is:% @", [myCar vin]); [релиз myCar]; [сток бассейна]; вернуть 0; }
Прежде всего мы создаем указатель на экземпляр SimpleCar с именем myCar. Далее мы используем alloc и init — они будут обсуждаться позже.
Далее, поскольку нам нужно передать NSNumber методу setVin, мы сделаем его здесь. Мы снова создаем указатель на экземпляр NSNumber с именем newVin и инициируем его с целочисленным значением 123. Константа «123» является целым числом, поэтому мы используем numberWithInt.
Далее мы вызываем наши методы, сначала мы указываем, кто должен получить сообщение (myCar), а затем используем метод setVin. После того, как двоеточие является значением, которое мы передаем методу, который является NSNumber, который мы создали ранее. Далее мы делаем то же самое, но вызываем метод setMake с двумя параметрами. Причина, по которой этим параметрам предшествует знак @, заключается в том, чтобы сообщить компилятору, что ниже приведена строка.
Наконец, мы выпускаем myCar, как мы закончили с этим — подробнее об этом позже в серии под управлением памятью.
Наш класс теперь работает, и чтобы увидеть доказательство, мы добавили несколько операторов NSLog для вывода значений в консоль. Если вы откроете консоль («Выполнить»> «Консоль»), а затем соберете и запустите свое приложение, вы должны увидеть вывод, подобный следующему:
Собственность и синтез
Если вы посмотрите на приведенный выше код, многое кажется совершенно бессмысленным и чрезмерным. Например, в наших методах получения все, что мы делаем — это возвращаем переменную экземпляра, но для этого требуется три строчки кода. Кроме того, в наших методах установки мы просто устанавливаем переменные экземпляра — по сути, все наши методы, за исключением нашего метода, который принимает два аргумента, кажутся раздутыми и мешающими. Objective-C решает эту проблему с помощью @property и @synthesize, которые заменяют наши методы доступа и позволяют значительно улучшить кодирование.
Вот как выглядит наш новый интерфейсный файл с использованием свойств:
#импорт@interface SimpleCar: NSObject { NSString * make; NSString * модель; NSNumber * vin; } @property (readwrite, retain) NSString * make; @property (readwrite, retain) NSString * модель; @property (перезаписать, сохранить) NSNumber * vin; // удобный метод - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @конец
Вау, это действительно намного короче. Так что же происходит с объявлениями @property? Сначала мы сообщаем компилятору, что мы объявляем свойство с помощью @property, затем мы следуем атрибутам для этого свойства. Атрибутами являются состояние чтения / записи свойства и управление памятью. Мы использовали readwrite для всех, что означает, что методы getter и setter динамически создаются для переменных нашего экземпляра (мы могли бы использовать только для чтения или только для чтения только для одной или другой). Причина, по которой мы используем сохранение, станет ясна в следующий раз, когда мы рассмотрим управление памятью
Прежде чем это сработает, нам нужно реализовать это в нашем файле реализации, мы делаем это с помощью @synthesize. Наш новый файл реализации выглядит следующим образом:
#import "SimpleCar.h" @implementation SimpleCar @synthesize make, model, vin; - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel { [self setMake: newMake]; [self setModel: newModel]; } @конец
Разве это не выглядит лучше? Думайте об этом так, @property заменяет все объявления методов интерфейса для методов получения и установки, а @synthesize заменяет сами фактические методы. Получатели и установщики теперь создаются динамически, и нам не нужно тратить время на их создание, если только нам не нужно делать что-то действительно особенное.
Завершение
Теперь у вас должна быть крепкая хватка классов, объектов и экземпляров. Конечно, вы еще не создаете классы, которые изменят мир, но это занимает время. Лучше учиться на собственном примере, поэтому, если вы не пишете код по ходу дела, обязательно загрузите исходные файлы и прочитайте их (и скомпилируйте), чтобы убедиться, что вы на 100% знаете, что происходит.
В следующий раз
Мы много говорили об управлении памятью в этом уроке, это очень важный вопрос, который нужно рассмотреть (каламбур), поэтому мы углубимся в это в следующий раз. Правда, это не самый забавный предмет или с которым проще всего смириться, но это абсолютно важно, если вы хотите стать опытным программистом на Objective-C.
Вызов
Задача на этой неделе может быть немного сложнее, но посмотрим, как вы справитесь. Прежде всего, если вы не скопировали весь код выше, загрузите исходные файлы, которые включены в эту статью. Задача состоит в том, чтобы добавить еще один класс в проект, но на этот раз он должен быть подклассом SimpleCar (помните, мы определяем родительский класс в файле интерфейса). Если вы можете сделать это, поиграйте и используйте унаследованные методы и попробуйте добавить свои собственные для таких вещей, как: размер двигателя, двери или высота.
Помните : если у вас есть какие-либо вопросы или вопросы, оставьте комментарий ниже или напишите мне в Twitter. Единственный глупый вопрос — тот, который вы не задавали — эта серия посвящена обучению, поэтому не стесняйтесь задавать вопросы!