Эта глава призвана помочь вам привыкнуть к стилю программирования 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 .