Objective-C — это простой язык программирования, разработанный как язык объектно-ориентированного программирования. Objective-C расширяет стандартные возможности ANSI-C, осуществляя поддержку таких возможностей, как описание классов, методов и свойств. Синтаксис языка в основном основан на языке Smalltalk — одном из первых ООП-языков.
Если у вас уже есть опыт работы с ООП-языками, то следующая информация поможет вам разобраться в синтаксисе Objective-C. Многие концепции ООП, такие как инкапсуляция, наследование и полиморфизм, также применяются в Objective-C. Но есть и некоторые отличия, которые отражены в данной статье и в других документах, доступных на официальном сайте для разработчиков.
Objective-C: Как подмножество C
Objective-C — это подмножество языка ANSI C, в котором поддерживается некоторый базовый синтаксис C. Также как и в C-коде, вы определяете заголовочный (header) файл и файл кода (source) чтобы было проще отделить объявление от реализации в вашем коде программы. Заголовочные файлы в Objective-C используют расширение файлов, прдставленное в Таблице 1.
Таблица 1 Расширения файлов для кода Objective-C
Расширение | Тип исходников |
---|---|
.h | Заголовочные (header) файлы. Cодержат классы, типы, функции и объявление констант. |
.m | Файлы кода (source). Это типовое расширение файлов для исходного кода как Objective-C, так и C-кода. |
.mm | Файлы кода (source). Файлы с таким расширением обычно содержат код C++ в дополнении к коду Objective-C и C. Это расширение используется только, если вы фактически обращаетесь к классам или особенностям C++ из вашего Objective-C кода. |
Когда вы захотите включить header файл в ваш исходный код, вы можете использвать стандартную директиву компилятора #include, но в Objective-C можно сделать проще. Директива #import идентична директиве #include, за исключением того, что она проверяет, не включался ли то же самый файл раньше. Во всех примерах и в документации по Objective-C предпочитается использовать #import, соответсвенно ваш код должен быть написан также.
Строковые переменные
Как в подмножестве C, в Objective-C поддерживается те же самые соглашения для того, чтобы определить строки как и в C. Другими словами, единичные символы заключаются в одинарные кавычки и строки заключаются в двойные кавычки. Однако, большинство структур (frameworks) в Objective-C не часто используют стиль описания строк как в C. Вместо этого, большинство frameworks раздают строки в объектах типа NSString.
Класс NSString обеспечивает упаковку объекта для строк, которые имеют все преимущества, ожидаемые вами, включая встроенное управление памятью для того, чтобы хранить строки произвольной длины, поддержку Unicode, утилит форматирования printf-стиля и т.п. Хотя обычно используются именно такие строки, Objective-C обеспечивает упрощеный метод (shorthand) для того, чтобы создать объекты NSString из значения константы. Чтобы использовать этот упрощенный метод все что вам нужно сделать — предопределить стандартную строку, заключенную в двойные кавычки с символом @, так как показано в примерах ниже:
NSString* myString = @"My Stringn"; NSString* anotherString = [NSString stringWithFormat:@"%d %s", 1, @"String"]; // Создание строки Objective-C из строки C NSString* fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding];
Классы
Как и в большинстве других объектно-ориентированных языках, классы в Objective-C обеспечивают основную конструкцию для формирования некоторых данных с действиями, которые воздействуют на эти данные. Объект — это просто экземпляр класса, который содержит в оперативной памяти копии переменных экземпляров класса, объявленных этим классом и указателями на методы класса.
Определение класса в Objective-C требует две различные части: интерфейс (interface) и реализация (implementation). Интерфейс определяет структуру экземпляров класса, а также instance-переменные и методы, связанные с классом. Реализация содержит код для описания методов класса. Иллюстрация 1 показывает синтаксис, объявляющий класс по имени MyClass, который наследуется из базового класса NSObject. Декларация класса всегда начинается с директивы компилятора @interface и заканчивается директивой @end. После имени класса следует имя родительского класса, отделенное двоеточием. Instance-переменные класса объявляются в блоке кода, который заключен в скобки ({ и }). После блока описания instance-переменных следует список методов, объявленных классом. После каждого объявления instance-переменной или метода ставится точка с запятой.
Иллюстрация 1 Определение класса
Листинг 1 показывает реализацию класса MyClass из предыдущего примера. Как и в декларации класса, реализация (implementation) класса заключена между двумя директивами компилятора — @implementation и @end. Эти директивы предоставляют определенную информацию, которая нужна компилятору для того, чтобы связать вложенные методы с соответствующим классом. Поэтому, определение метода соответствует заданному определению в интерфейсе, кроме включения блока с кодом.
Листинг 1 Реализация класса
@implementation MyClass - (id)initWithString:(NSString *) aName { if (self = [super init]) { count count = 0; data = nil; name = [aName copy]; return self; } } + (MyClass *)createMyClassWithString: (NSString *) aName { return [[[self alloc] initWithString:aName] autorelease]; } @end
Примечание: Хотя предыдущая реализация класса объявляет только методы, однако классы могут также объявлять и свойства. Для получения дополнительной информации о свойствах, см. в разделе «Свойства» данного материала.
Когда вы храните объекты внутри переменных, вы так или иначе используете ссылочный тип (pointer type). Objective-C поддерживает как явное, так и неявное объявление типов переменных, содержащих объекты. Явно объявленные указатели включают название класса в объявлении типа переменной. Неявно объявленный тип указателя, в отличии от явного, использует тип id для объектов. Неявно объявленный тип указателя чаще всего используется для таких вещей, как коллекционные классы, где может быть неизвестным точный тип объектов коллекции. Если вы привыкли использовать языки, где используется только явное объявление типов, тогда наверное вы будете думать, что использование неявного объявления типа переменных вызовет кучу проблем. Однако, на самом деле, это обеспечивают огромную гибкость и намного большую динамичность в программах Objective-C.
Вот пример обоих типов объявления переменных для класса Myclass:
MyClass* myObject1; // Явное объявление типа id myObject2; // Неявное объявление типа
Методы
Класс в Objective-C может объявлять два типа методов: методы экземпляра класса и методы класса. Метод экземпляра класса — метод, выполнение которого — в границах видимости определенного экземпляра класса. Другими словами, прежде, чем вы вызываете метод экземпляра класса, вы должны сначала создать этот экземпляр класса. Методы класса, к примеру, не требуют, чтобы вы создавали экземпляр класса, но поговорим об этом позже.
Объявление метода состоит из идентификатора типа метода, типа возвращаемого значения, одного или более ключевых слов сигнатуры, а также тип свойства и информации о имени. Иллюстрация 2 показывает объявление метода экземпляра класса insertObject:atIndex: Объявлению предшествуют знак минуса (-) , который указывает, что это метод экземпляра класса. Фактическое имя метода (insertObject:atIndex:) — это связь всех ключевых слов сигнатуры, включая символы двоеточия. Символы двоеточия объявляют присутствие свойства. Если у метода нет никаких свойств, то опустите двоеточие только после первого ключевого слова сигнатуры. В этом примере метод получает два свойства.
Иллюстрация 2 Синтаксис объявления метода
Когда вы хотите вызвать метод, вы делаете это через «обмен сообщениями» с соответствующим объектом. Сообщение в этом случае — это сигнатура метода вместе с информацией о свойстве, необходимые методу. Все сообщения, которые Вы посылаете объекту, отправляются динамически, таким образом облегчая поведение полиморфизма классов в Objective-C. Другими словами, если подкласс определяет метод с той же самой сигнатурой, как один из ее родительских классов, сначала сообщение получает подкласс и может решить отправлять сообщение его родителю или нет.
Сообщения заключаются в квадратные скобки [ и ]. Внутри скобок указывается объект, которому предназначено сообщение (включая все необходимые свойства) и само сообщение. Например, чтобы послать сообщение insertObject:atIndex: объекту из myArray переменной, следует использовать следующий синтаксис:
[myArray insertObject:anObj atIndex:0];
Чтобы избежать объявления множества локальных переменных хранящих временные значения, Objective-C позволяет вкладывать сообщения друг в друга. Возвращаемое значение из каждого вложенного сообщения используется как свойство, или как цель для другого сообщения. Например, вы можете заменить любую из переменных, используемых в предыдущем примере, сообщениями для того чтобы получить значения. Таким образом, если бы у вас был другой объект, названный myAppObject, у которого были бы методы обращения к объекту типа массив и объект, который необходимо вставить в массив, то вы могли бы написать предыдущий пример, таким образом:
[[myAppObject getArray] insertObject:[myAppObject getObjectToInsert] atIndex:0];
Хотя предыдущие примеры посылали сообщения экземпляру класса, вы можете также посылать сообщения непосредственно классу. Когда сообщение передается классу, метод должен быть определен как метод класса, а не как метод экземпляра класса. Методы класса чем то похожи на статические участники (static members) в классах C++.
Обычно методы класса используются как фабрика методов с целью создания новых экземпляров класса или для предоставления доступа к определенной части допустимой информации класса. Синтаксис объявления метода класса схож с синтаксисом описания методов экземпляра класса, но с одним исключением. Вместо того знака «минус» в определении идентификатора типа метода, используется знак плюс (+).
Следующий пример демонстрирует использование метода класса как фабрики методов для класса. В этом случае метод arrayWithCapacity: — метод класса из класса NSMutableArray, который размещает и инициализирует новый экземпляр класса и возвращает его в ваш код.
NSMutableArray* myArray = nil; // nill - это то же самое что и NULL (пустой указатель) // Создание нового массива и назначение его переменной myArray myArray = [NSMutableArray arrayWithCapacity:0];
Свойства
Свойства — удобное средство для замены объявления средств доступа метода (accessor method). Свойства не создают новые переменные экземпляра в объявленом класск. На самом деле, свойства — это упрощенный способ (shorthand) для определения методов, обращающихся к существующим переменным экземплярам. Классы, которые подставляют переменные экземпляра, могут использовать обозначение свойства вместо того, чтобы использовать синтаксис getter и setter. Классы также могут использовать свойства для того, чтобы подставить «виртуальные» переменные экземпляров класса — данные вычисленные динамически, но фактически не сохраненые в переменных экземплярах класса.
Проще говоря, свойства позволяют сократить количество избыточного кода, который вы будете писать. Поскольку большинство методов доступа осуществляется именно подобным способом, свойства избавляют нас от необходимости явно устанавливать методы getter и setter для каждой переменной экземпляра, указанной в классе. Вместо этого вы описываете поведение, которое вы хотите использовать для объявления свойств и затем синтезируете фактические getter и setter методы, основанные на этом объявлении, прямо во время компиляции.
Включаете объявления свойств с объявлениями метода в вашем интерфейс-классе. Для объявления свойств используют директиву @property, сопровождаемую информацией о типе и имени свойства. Вы можете также описывать свойства с собственными параметрами, которые определяют, как методы доступа должны себя вести. Ниже приведены примеры объявления нескольких простых свойств:
@property BOOL flag; @property (copy) NSString* nameObject; // Копирование объекта во время присваивания. @property (readonly) UIView* rootView; // Создание только метода getter.
Еще один удобный нюанс в применении свойств — это то, что вы можете использовать синтаксис с точкой, обращаясь к свойствам вашего кода. А вот пример его использования:
myObject.flag = YES; CGRect viewFrame = myObject.rootView.frame;
Хотя имена объекта и свойства в предыдущем примере надуманы, они все же демонстрируют гибкость свойств. Синтаксис с применением точки фактически маскирует соответствующий набор вызовов метода. Каждое доступное для чтения свойство поддерживается методом с таким же именем, что и само свойство. Каждое доступное для записи свойство поддерживается дополнительным методом формы setPropertyName: , где имя свойства начинается с большой буквы. (Эти методы являются фактической реализация свойств и являются причиной, по которой вы можете включать объявления свойства для атрибутов вашего класса не поддерживаемых переменными экземпляра класса). Давайте перепишем предыдущий пример с использованием методов вместо свойств:
[myObject setFlag:YES]; CGRect viewFrame = [[myObject rootView] frame];
Для того чтобы узнать больше о том, как объявлять свойства в своих собственных классах, прочтите раздел «Properties» в документе The Objective-C 2.0 Programming Language.
Протоколы и Делегаты
Протокол объявляет методы, которые могут быть реализованы любым из классов. Но сами по себе протоколы, при этом, не являются классами. Они просто определяют интерфейс, за реализацию которого ответственны другие объекты. Когда вы реализуете методы протокола в одном из ваших классов, то можно сказать, что ваш класс соответствует этому протоколу.
В iPhone OS обычно протоколы используются для делегирования объектов. Делегированный объект — это объект, который действует от имени (или под руководством) другого объекта. Чтобы лучше понять как взаимодействуют между собой протоколы, делегаты и другие объекты, давайте рассмотрим пример.
Например, класс UIApplication реализует нужное нам поведение приложения. Вместо того, чтобы заставлять подкласс UIApplication получать простые запросы о текущем состоянии приложения, класс UIApplication передает эти запросы назначенному объекту-делегату, вызывая при этом определенные методы. Тоесть, объект, который реализует методы протокола UIApplicationDelegate, может получать эти запросы и выдавать на них соответствующий ответ.
Объявление протокола похоже на интерфейс класса, за исключением того, что у протоколов нет родительского класса, и они не определяют переменные экземпляра. Следующий пример показывает простое объявление протокола с одним методом:
@protocol MyProtocol - (void)myProtocolMethod; @end
В случае, когда используется много протоколов делегирования, принятие протокола — это просто вопрос реализации методов определенных этим протоколом. Есть некоторые протоколы, которые требуют, чтобы вы ясно заявили, что вы поддерживаете протокол, и тогда протоколы могут определять оба метода, как необходимые, так и опциональные. Чем глубже вы увлекаетесь разработкой приложений, тем больше времени вам придется потратить на то, чтобы почитать раздел «Protocols» из документа The Objective-C 2.0 Programming Language.
Хотите знать больше?
Предыдущая информация была предназначена прежде всего для того, чтобы ознакомить вас с базовыми основами языка Objective-C. Охваченный в данном материале предмет отражает лишь некоторые особенности языка, с которыми вы наверняка встретитесь. Однако вам необходимо знать, что описанные здесь особенности — не единственные, поэтому мы всегда поощряем читать больше об Objective-C в документе The Objective-C 2.0 Programming Language.
Это первая версия перевода документа, которая доступна по адресу: http://www.insk.org/category/devteam/start/objectivecprimer/
Оригинал статьи (англ.) находится по адресу: http://developer.apple.com/iphone/gettingstarted/docs/objectivecprimer.action
Перевод взят с сайта http://www.insk.org/2008/10/16/objectivecprimer/
Немає коментарів:
Дописати коментар