Эта глава призвана помочь вам привыкнуть к стилю программирования Objective-C. К концу этой главы вы сможете создавать объекты, создавать и вызывать методы, а также объявлять свойства. Помните, что цель состоит в том, чтобы предоставить очень краткий обзор основных объектно-ориентированных аспектов Objective-C, а не подробное описание каждого компонента. В последующих главах описываются многие концептуальные детали, опущенные в этой главе.
Создание класса
Включенный пример кода: HelloObjectiveC с классом
Давайте углубимся и создадим новый файл Objective-C. В Xcode IDE перейдите к « Файл» > « Создать» > « Файл» или используйте ярлык Cmd + N, чтобы добавить файл в проект. В следующем диалоговом окне вы можете выбрать, какой тип файла вы хотите создать. Под категорией Какао Touch выберите класс Objective-C .
Вам предоставляется возможность указать имя для вашего нового класса. Давайте назовем наш класс Person . Для родительского класса используйте NSObject , который является объектом верхнего уровня, от которого наследуются все классы Objective-C.
Нажатие Next откроет файловый браузер и попросит вас ввести группу для вашего класса, а также цель . Используйте группу по умолчанию, которая должна быть HelloObjectiveC . Группы — это специфический механизм Xcode для группировки похожих файлов, но они не реализованы на уровне файлов. Наш новый класс появится в той же папке, что и остальные файлы проекта, независимо от того, в какую группу он входит. Для целей убедитесь, что выбран HelloObjectiveC . Это гарантирует, что новый класс будет скомпилирован всякий раз, когда мы создаем цель HelloObjectiveC.
Наконец, нажмите Создать, чтобы создать класс. В навигаторе файлов XCode теперь вы должны найти два новых класса: Person.h и Person.m . Как и язык программирования C, Objective-C использует .h в качестве расширения для заголовочных файлов, которые содержат интерфейс для определенной функции или класса — это не следует путать с интерфейсом C #, который называется в Objective- протоколом. C. Файл .m является соответствующей реализацией для класса Person .
Отделение интерфейса класса от его реализации позволяет скрыть детали реализации от сторонних объектов. Другие файлы, которые должны взаимодействовать с классом, импортируют файл заголовка, а не файл реализации . Это обеспечивает абстрактное определение, необходимое для вызова методов и доступа к свойствам, будучи полностью независимым от реализации класса.
Компоненты класса
В навигаторе проекта выберите Person.h, чтобы открыть его на панели редактора. Вы должны увидеть следующий код Objective-C:
|
1
2
3
4
5
|
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
|
Директива #import включает другой файл в текущем контексте. Включение заголовочного файла дает нам доступ ко всем классам и функциям, которые он определяет. В данном случае мы включили основу фонда. Платформа Foundation определяет базовые конструкции языка Objective C, такие как строки, массивы, словари и т. Д., Так что это необходимая часть практически каждой программы Objective C.
Директива @interface начинает интерфейс для класса. Затем следует имя класса Person , за которым следует двоеточие и родительский класс NSObject . Как отмечалось ранее, NSObject является объектом верхнего уровня в Objective-C. Он содержит необходимые методы для создания и уничтожения экземпляров, а также некоторые другие полезные функции, общие для всех объектов.
Любые методы или свойства будут объявлены до директивы @end , но прямо сейчас Person.h — пустой интерфейс. Мы изменим это через минуту, но сначала давайте взглянем на файл реализации Person.m :
|
1
2
3
4
5
|
#import «Person.h»
@implementation Person
@end
|
Это очень похоже на файл заголовка, но включает заголовок Person.h . Файлы реализации должны содержать связанный с ними заголовок, иначе они не смогут найти класс, который пытаются реализовать.
Также обратите внимание, что эта директива #import использует кавычки вместо угловых скобок. Кавычки следует использовать для импорта локальных заголовков, а квадратные скобки указывают глобальные заголовки. Глобальные заголовки находятся за пределами проекта и связаны с компилятором в процессе сборки. Стандартные рамки Apple всегда заключаются в угловые скобки, а файлы вашего проекта следует импортировать с кавычками.
И, конечно же, файл .m использует директиву @implementation вместо @interface . Обратите внимание, что вам не нужно указывать родительский класс здесь, так как эта информация уже содержится в заголовке.
Определение методов
Далее мы добавим объявление метода в класс Person . Помните, что это двухэтапный процесс: сначала мы должны добавить его к интерфейсу, а затем к реализации. Итак, измените Person.h на следующее:
|
1
2
3
4
5
6
7
|
#import <Foundation/Foundation.h>
@interface Person : NSObject
— (void)sayHello;
@end
|
Как видите, методы экземпляра объявляются с дефисом, типом возврата в скобках ( void ), за которым следуют имя метода и точка с запятой. Теперь, когда у нас есть это в интерфейсе, переключитесь на Person.m, чтобы определить реализацию. Обратите внимание, что Xcode добавил маленький желтый треугольник рядом со @implementation . Если вы щелкнете по нему, вы увидите предупреждающее сообщение с надписью Незавершенная реализация . Это одна из многочисленных функций отладки Xcode. Давайте исправим эту проблему, изменив Person.m следующим образом:
|
1
2
3
4
5
6
7
8
9
|
#import «Person.h»
@implementation Person
— (void)sayHello {
NSLog(@»Hello, my name is HAL.»);
}
@end
|
Как и объявление интерфейса, реализация метода экземпляра начинается с дефиса, возвращаемого типа и имени функции. Сама реализация определяется в фигурных скобках после имени метода, как метод C #. Для sayHello мы просто выводим сообщение на консоль, используя NSLog() .
Когда вы печатаете, Xcode представляет некоторые варианты автозаполнения, и он также должен был закрыть ваши фигурные скобки для вас. Эти поведения можно изменить, перейдя в Xcode > Preferences … в строке меню и щелкнув значок редактирования текста .
Создание объектов
Давайте попробуем создать экземпляр нашего класса Person и вызвать наш новый метод sayHello . Помните, что, как и любая C-программа, main() является точкой входа в наше приложение HelloObjectiveC . Итак, вернувшись в main.m , измените NSLog(@"Hello, World!"); к следующему:
|
01
02
03
04
05
06
07
08
09
10
11
|
#import <Foundation/Foundation.h>
#import «Person.h»
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *somePerson = [[Person alloc] init];
}
return 0;
}
|
Выражение Person *somePerson объявляет переменную somePerson и сообщает компилятору, что он будет содержать экземпляр класса Person . Звездочка рядом с именем переменной указывает, что это указатель , который является наиболее распространенным способом ссылки на объекты в Objective-C. Мы обсудим указатели более подробно в будущем.
Затем код [[Person alloc] init] создает новый экземпляр класса Person . Для обозначения в квадратных скобках может потребоваться некоторое привыкание, но концептуально оно совпадает с круглыми скобками, используемыми для вызовов методов в C # и других языках стиля Simula. Предыдущий пример кода эквивалентен следующему в C #:
Person somePerson = new Person (); somePerson.init ();
Вызов [Person alloc] выделяет память, необходимую для нового экземпляра, а вызов init используется для выполнения любого вида пользовательского кода инициализации. Обратите внимание, что в Objective-C нет «методов конструктора», как в C # или C ++ — вы должны вручную вызвать метод init (или какой-либо его вариант) для настройки вашего объекта. В результате практически все объекты создаются в Objective-C в два этапа: выделить, а затем инициализировать. Вы увидите этот шаблон довольно часто в программах Objective-C.
Методы вызова
Теперь, когда у нас есть объект для работы, мы можем вызвать наш метод sayHello . Обратите внимание, что правильной терминологией в Objective-C является «отправка сообщения», а не «вызов метода», но для наших целей мы можем рассматривать их как синонимы. Добавьте следующую строку в main.m :
|
1
|
[somePerson sayHello];
|
Как и методы alloc / init в предыдущем примере, при вызове пользовательского метода используются квадратные скобки. Опять же, это то же самое, что выполнить somePerson.sayHello() в C #. При запуске вашей программы должно отображаться Hello, my name is HAL. на панели вывода Xcode:
Добавление параметров метода
Помимо квадратных скобок, соглашения об именах методов в Objective-C являются одним из самых больших изменений для разработчиков, работающих на C #, C ++, Java, Python или почти любом другом языке, который не является Smalltalk. Имена методов Objective-C разработаны как можно более описательными. Идея состоит в том, чтобы определить метод таким образом, чтобы чтение вслух буквально сообщало вам, что он делает.
В качестве примера давайте добавим параметр name в наш метод sayHello . Сначала нам нужно обновить объявление метода в заголовке ( Person.h ):
|
1
|
— (void)sayHelloToName:(NSString *)aName;
|
Добавление параметра фактически изменило имя функции — параметр не является изолированной сущностью, как в C # (например, sayHello(name) ). Часть (NSString *) определяет тип данных параметра, а aName — фактическая переменная, к которой можно получить доступ в коде реализации, который мы сейчас определим. Измените sayHello в Person.m на следующий пример кода. Xcode должен автоматически заполнить имя нового метода, когда вы начнете его набирать.
|
1
2
3
|
— (void)sayHelloToName:(NSString *)aName {
NSLog(@»Hello %@, my name is HAL.», aName);
}
|
Эта новая конфигурация NSLog() использует строку формата для добавления аргумента aName к выводу. Мы рассмотрим NSLog() более подробно в следующей главе, но пока все, что вам нужно знать, это то, что он заменяет %@ в строке формата на aName . Это примерно эквивалентно String.Format() в C #.
Вызов параметра aName может показаться излишним с sayHelloToName , но он имеет больше смысла, когда вы читаете метод так, как он будет вызван. В main.m измените вызов sayHello на:
|
1
|
[somePerson sayHelloToName:@»Bill»];
|
Теперь вы сможете запустить свою программу и увидеть Hello Bill, my name is HAL. в панели вывода. Как видите, имена методов Objective-C являются подробными, но достаточно информативными. В отличие от вызова sayHello(name) стиле C #, Objective-C очень трудно случайно передать неправильное значение методу. Конечно, компромисс заключается в том, что имена методов длинные, но именно поэтому XCode предоставляет такую удобную функцию автозаполнения. В этой книге мы увидим еще много подробных (и более практичных) примеров имен методов Objective-C.
Определение свойств
Включенный пример кода: со свойствами
Как и в любом объектно-ориентированном языке, методы Objective-C являются средством управления внутренним состоянием объекта. Это состояние обычно представлено как набор свойств, прикрепленных к объекту. Например, мы можем добавить свойство name в наш интерфейс Person для динамического хранения имени каждого экземпляра:
|
1
|
@property (copy) NSString *name;
|
Объявление @property начинает новое свойство, кортеж (copy) определяет поведение свойства, а NSString *name определяет свойство с именем name которое содержит строковое значение. Как правило, объявления свойств помещаются перед объявлениями методов, но пока они находятся между @interface и @end в Person.h , все будет в порядке.
Использование @property вместо личных атрибутов дает вам доступ к директиве @synthesize в файле реализации. Это позволяет автоматически создавать методы доступа для связанного свойства. Например, в Person.m добавьте следующее (опять же, реализации свойств обычно предшествуют реализациям методов):
|
1
|
@synthesize name = _name;
|
@synthesize — это удобная директива, которая указывает компилятору генерировать методы getter и setter для свойства. Часть после знака = используется как переменная экземпляра (то есть закрытый член) для свойства, что означает, что мы можем использовать _name для доступа к свойству name внутри Person.m . Например, попробуйте изменить метод sayHelloToName на:
|
1
2
3
|
— (void)sayHelloToName:(NSString *)aName {
NSLog(@»Hello %@, my name is %@.», aName, _name);
}
|
По умолчанию имя метода получателя совпадает с именем свойства, и установщик set перед ним заглавное имя свойства. Таким образом, мы можем динамически установить имя объекта Person , изменив main.m на следующее:
|
1
2
3
|
Person *somePerson = [[Person alloc] init];
[somePerson setName:@»HAL 9000″];
[somePerson sayHelloToName:@»Bill»];
|
При запуске вашей программы теперь должен появиться Hello Bill, my name is HAL 9000 .
Резюме
В этой главе представлены основные компоненты класса Objective-C. Мы узнали, как разделять классы на интерфейс ( .h ) и файлы реализации ( .m ), создавать экземпляры объектов, определять и вызывать методы и объявлять свойства. Надеюсь, вы чувствуете себя немного более комфортно с нотацией Objective-C в квадратных скобках и другими синтаксическими причудами.
Помните, что эта глава была разработана, чтобы быть быстрым введением в ООП-конструкции Objective-C, а не углубленным обсуждением каждого компонента. В следующих главах мы более подробно рассмотрим типы данных, объявления свойств, определения методов, а также общие шаблоны проектирования программ Objective-C.
Этот урок представляет собой главу из Objective-C, лаконично , бесплатную электронную книгу от команды Syncfusion .