Статьи

Цель-C Кратко: Привет Цель-C

Эта глава призвана помочь вам привыкнуть к стилю программирования Objective-C. К концу этой главы вы сможете создавать объекты, создавать и вызывать методы, а также объявлять свойства. Помните, что цель состоит в том, чтобы предоставить очень краткий обзор основных объектно-ориентированных аспектов Objective-C, а не подробное описание каждого компонента. В последующих главах описываются многие концептуальные детали, опущенные в этой главе.


Включенный пример кода: HelloObjectiveC с классом

Давайте углубимся и создадим новый файл Objective-C. В Xcode IDE перейдите к « Файл» > « Создать» > « Файл» или используйте ярлык Cmd + N, чтобы добавить файл в проект. В следующем диалоговом окне вы можете выбрать, какой тип файла вы хотите создать. Под категорией Какао Touch выберите класс Objective-C .

Рисунок 10. Значок класса Objective C

Значок класса Objective-C

Вам предоставляется возможность указать имя для вашего нового класса. Давайте назовем наш класс Person . Для родительского класса используйте NSObject , который является объектом верхнего уровня, от которого наследуются все классы Objective-C.

Рисунок 11 Определение нового класса Person

Определение нового класса Person

Нажатие Next откроет файловый браузер и попросит вас ввести группу для вашего класса, а также цель . Используйте группу по умолчанию, которая должна быть HelloObjectiveC . Группы — это специфический механизм Xcode для группировки похожих файлов, но они не реализованы на уровне файлов. Наш новый класс появится в той же папке, что и остальные файлы проекта, независимо от того, в какую группу он входит. Для целей убедитесь, что выбран HelloObjectiveC . Это гарантирует, что новый класс будет скомпилирован всякий раз, когда мы создаем цель HelloObjectiveC.

Рисунок 12. Выбор целей сборки для нового класса.

Выбор целей сборки для нового класса

Наконец, нажмите Создать, чтобы создать класс. В навигаторе файлов 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 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:

Рисунок 13 Выходные данные, генерируемые методом sayHello

Выходные данные, полученные из метода sayHello

Помимо квадратных скобок, соглашения об именах методов в 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 .