Расширение файлов objective c
Objective-C — это простой язык программирования, разработанный как язык объектно-ориентированного программирования. Objective-C расширяет стандартные возможности ANSI-C, осуществляя поддержку таких возможностей, как описание классов, методов и свойств. Синтаксис языка в основном основан на языке Smalltalk — одном из первых ООП-языков.
Если у вас уже есть опыт работы с ООП-языками, то следующая информация поможет вам разобраться в синтаксисе Objective-C. Многие концепции ООП, такие как инкапсуляция, наследование и полиморфизм, также применяются в Objective-C. Но есть и некоторые отличия, которые отражены в данной статье и в других документах, доступных на официальном сайте для разработчиков.
Если же вы не программировали раньше в языках ООП, тогда вам нужно усвоить некоторые базовые концепции, перед тем как приступить к разработке приложений. Использование объектов ООП является фундаментальным в работе iPhone, и понимание их использования и взаимодействия между ними важны для программирования. Для того чтобы понять концепции ООП, изучите Object-Oriented Programming with Objective-C. Вы также можете изучить Cocoa Fundamentals Guide чтобы узнать о применении концепций ООП в Cocoa. Для более детального изучения синтаксиса языка Objective-C вы можете изучить The Objective-C 2.0 Programming Language.
Свойства
Ранее для изменения и чтения instance variables необходимо было писать методы возврата и задания значения(т.н. getters and setters), теперь можно писать так:
@interface Person: NSObject >
@property(readonly) NSString *name;
@property(readonly) int age;
-(id)initWithName:(NSString)name age:(int)age;
end
Получить имя можно так:
NSString *name = aPerson.name;
Строковые переменные
Как в подмножестве C, в Objective-C поддерживается те же самые соглашения для того, чтобы определить строки как и в C. Другими словами, единичные символы заключаются в одинарные кавычки и строки заключаются в двойные кавычки. Однако, большинство структур (frameworks) в Objective-C не часто используют стиль описания строк как в C. Вместо этого, большинство frameworks раздают строки в объектах типа NSString.
Класс NSString обеспечивает упаковку объекта для строк, которые имеют все преимущества, ожидаемые вами, включая встроенное управление памятью для того, чтобы хранить строки произвольной длины, поддержку Unicode, утилит форматирования printf-стиля и т.п. Хотя обычно используются именно такие строки, Objective-C обеспечивает упрощеный метод (shorthand) для того, чтобы создать объекты NSString из значения константы. Чтобы использовать этот упрощенный метод все что вам нужно сделать — предопределить стандартную строку, заключенную в двойные кавычки с символом @, так как показано в примерах ниже:
Исключения
Есть два основных подхода к обработке ошибок: глобальная статусная переменная, значение которой информирует об успешности выполнения предыдущей операции, и генерация исключений. Суть обоих в том, что код, в котором произошла ошибка, надеется, что решить ее сможет вызвавший его код, поэтому возвращает управление ему, сообщая о произошедшей ситуации как можно более подробно. Objective-C поддерживает оба эти подхода.
Исключение – это объект некоторого класса. Он (даже своим типом) несет в себе некоторую информацию о произошедшей ситуации. Для удобства в Cocoa имеется класс NSException, который можно инициализировать двумя объектами NSString и одним объектом произвольного класса (тип id):
Сгенерировать исключение и, тем самым, запустить механизм раскрутки стека вызовов, можно с помощью оператора @throw. Чтобы перхватить сгенерированное исключение, участок кода, где возможна его генерация, необходимо заключить в специальный блок с заглавием try (такие блоки могут быть вложенными). А затем, после этого блока, поставить блок с заглавием catch(), где в круглых скобках указать тип предполагаемого исключения. Блоков catch() после блока try может быть несколько. После генерации исключения управление, раскручивая стек, выходит из блока try и, проверяя по очереди все блоки catch(), попадает именно в тот блок catch(), в фигурных скобках которого стоит такой тип, к которому тип исключения приводится неявно (точное совпадение, указатель на базовый класс или id). Если исключение по типу не совпало ни с одним блоком catch(), управление продолжает раскрутку стека. Если после блока с заглавием try стоит блок с заглавием finally, то управление передастся ему независимо от того, произошло ли в блоке try исключение (и обработан какой-нибудь блок catch()), или выполнилась его последняя инструкция. Ниже приведен пример работы с объектом класса Cup в методе fill которого происходит исключение:
В блоке finally удобно освобождать ресурсы, выделенные в блоке try, но не освобожденные по причине сгенерированного исключения.
5 Answers 5
Methods in class extensions
It never used to be the case that you didn't need to declare your private methods. Until recently, you needed to declare your private methods somewhere, and most people chose a class extension to do so. From Xcode 4.4 (I believe), the compiler is clever enough to determine which methods are meant to be private within that implementation, removing the need to declare them elsewhere.
Variables in class extensions
As for examples 3 and 4, be careful. Within a class extension, the variable is an instance variable to that class (example 3). Example 4 declares a global variable (due to the fact it follows global variable semantics from C). Stick with example 3 for your private instance variables.
Coding conventions
As for the coding convention, it's up to the developer/team to decide whether to use an underscore or not. Our team uses m_ for private instance variables. Apple in their documentation suggest using underscores (that's the naming style for the underlying instance variables for synthesized properties). The important thing is, to be consistent throughout your code.
Большинство операционных систем имеют стандартный каталог предоставленный специально для целей временного хранения файлов. Другие системы также обеспечивают другую временную папку для каждого пользователя. Точное место отличается в зависимости от платформы. Самым безопасным будет использование NSTemporaryDirectory() , чтобы определить соответствующий каталог. Эта функция возвращает временный каталог для текущего пользователя в виде объекта NSString .
Следующий фрагмент кода определяет и затем отображает временный каталог, используя NSTemporaryDirectory() функцию:
Определение домашней папки пользователя
Домашний каталог текущего пользователя может быть определен с помощью NSHomeDirectory() функции. Эта функция не принимает аргументов и возвращает объект NSString , содержащий путь к домашней директории пользователя:
Определение домашней папки конкретно заданного пользователя
Домашний каталог любого пользователя в системе может быть получен с помощью NSHomeDirectoryForUser() функции. Эта функция принимает в качестве единственного аргумента объекта NSString , содержащий имя пользователя и возвращает другой объект NSString , содержащий соответствующий домашний каталог:
Если заданного пользователя не существует, запрос вернет nil.
Извлечение имени файла
Как уже говорилось ранее, путь может состоять из каталога, в котором находится файл, за которым следует имя файла. Общим требованием при работе с файлами при программировании на любом языке является извлечение только имя файла из пути. Это может быть легко достигнуто с помощью lastPathComponent метод:
Извлечение расширения файла
Имена файлов после '.' имеют некое расширение. Например, расширение файла myfile.txt является TXT. Расширение файла может быть извлечено из пути с использованием метода pathExtension :
Стандартизация пути
Удивительно, как быстро путь может осложниться, особенно когда пользователь перемещаться по файловой системе. Пакет NSUtilities предоставляет метод stringByStandardizingPath . В следующем коде мы будем использовать этот метод, чтобы сделать упрощение пути:
Например: ~demo/objc/code/../header/./../includes/mycode.h
В результате выполнения получим правильный путь: /Users/demo/objc/includes/mycode.h
Разложение пути на его составляющие директории
Метод pathComponents извлекает различные части пути, которые составляют полный путь и возвращает их в NSArray :
В результате получим массив-список директорий из которых состоит путь:
Методы
Класс в Objective-C может объявлять два типа методов: методы экземпляра класса и методы класса. Метод экземпляра класса — метод, выполнение которого — в границах видимости определенного экземпляра класса. Другими словами, прежде, чем вы вызываете метод экземпляра класса, вы должны сначала создать этот экземпляр класса. Методы класса, к примеру, не требуют, чтобы вы создавали экземпляр класса, но поговорим об этом позже.
Объявление метода состоит из идентификатора типа метода, типа возвращаемого значения, одного или более ключевых слов сигнатуры, а также тип свойства и информации о имени. Иллюстрация 2 показывает объявление метода экземпляра класса insertObject:atIndex: Объявлению предшествуют знак минуса (-) , который указывает, что это метод экземпляра класса. Фактическое имя метода (insertObject:atIndex:) — это связь всех ключевых слов сигнатуры, включая символы двоеточия. Символы двоеточия объявляют присутствие свойства. Если у метода нет никаких свойств, то опустите двоеточие только после первого ключевого слова сигнатуры. В этом примере метод получает два свойства.
Иллюстрация 2 Синтаксис объявления метода
Обычно методы класса используются как фабрика методов с целью создания новых экземпляров класса или для предоставления доступа к определенной части допустимой информации класса. Синтаксис объявления метода класса схож с синтаксисом описания методов экземпляра класса, но с одним исключением. Вместо того знака «минус» в определении идентификатора типа метода, используется знак плюс (+).
Следующий пример демонстрирует использование метода класса как фабрики методов для класса. В этом случае метод arrayWithCapacity: — метод класса из класса NSMutableArray, который размещает и инициализирует новый экземпляр класса и возвращает его в ваш код.
Свойства
Свойства — удобное средство для замены объявления средств доступа метода (accessor method). Свойства не создают новые переменные экземпляра в объявленом класск. На самом деле, свойства — это упрощенный способ (shorthand) для определения методов, обращающихся к существующим переменным экземплярам. Классы, которые подставляют переменные экземпляра, могут использовать обозначение свойства вместо того, чтобы использовать синтаксис getter и setter. Классы также могут использовать свойства для того, чтобы подставить «виртуальные» переменные экземпляров класса — данные вычисленные динамически, но фактически не сохраненые в переменных экземплярах класса.
Проще говоря, свойства позволяют сократить количество избыточного кода, который вы будете писать. Поскольку большинство методов доступа осуществляется именно подобным способом, свойства избавляют нас от необходимости явно устанавливать методы getter и setter для каждой переменной экземпляра, указанной в классе. Вместо этого вы описываете поведение, которое вы хотите использовать для объявления свойств и затем синтезируете фактические getter и setter методы, основанные на этом объявлении, прямо во время компиляции.
Включаете объявления свойств с объявлениями метода в вашем интерфейс-классе. Для объявления свойств используют директиву @property, сопровождаемую информацией о типе и имени свойства. Вы можете также описывать свойства с собственными параметрами, которые определяют, как методы доступа должны себя вести. Ниже приведены примеры объявления нескольких простых свойств:
Еще один удобный нюанс в применении свойств — это то, что вы можете использовать синтаксис с точкой, обращаясь к свойствам вашего кода. А вот пример его использования:
Хотя имена объекта и свойства в предыдущем примере надуманы, они все же демонстрируют гибкость свойств. Синтаксис с применением точки фактически маскирует соответствующий набор вызовов метода. Каждое доступное для чтения свойство поддерживается методом с таким же именем, что и само свойство. Каждое доступное для записи свойство поддерживается дополнительным методом формы setPropertyName: , где имя свойства начинается с большой буквы. (Эти методы являются фактической реализация свойств и являются причиной, по которой вы можете включать объявления свойства для атрибутов вашего класса не поддерживаемых переменными экземпляра класса). Давайте перепишем предыдущий пример с использованием методов вместо свойств:
Для того чтобы узнать больше о том, как объявлять свойства в своих собственных классах, прочтите раздел «Properties» в документе The Objective-C 2.0 Programming Language.
Время жизни объекта
Реализация init очень важна. Это конструктор класса. Конструкторы отличаются тем, что возвращаеют id и их названия всегда начинается со слова init, а конструктор по умолчанию – это и есть просто init. Схема любого конструктора примерно следующая:
Вот типичный специализированный (не по умолчанию) конструктор для класса с двумя членами типа некоторого класса и одним целочисленным инвариантом:
Реализация release и retain для NSObject идеологически примерно следующая, и ее не нужно переопределять в производных классах, в силу отсутствия доступа к инварианту счетчика ссылок:
Создание новых классов
Все новые директивы компилятору в языке Objective-C начинаются с символа @. Как и в С++ описание класса и его реализация разделены (обычно описание помещается в заголовочные файлы с расширением h, а реализации — в файлы с расширением m).
Ниже приводится общая структура описания нового класса:
@interface ClassName: SuperClass
instance variable declarations
>
method declarations
end
В версии runtime от Apple все классы имеют общего предка — класс NSObject, содержащий целый ряд важных методов. Описание переменных ничем не отличается от описания переменных в структурах в языке С:
@interface Rect: NSObject
float width;
float height;
BOOL isFilled;
NSColor * color;
>
end
Каждое описание начинается со знака плюс или минус. Знак плюс обозначает, что данный метод является методом класса (т.е. его можно посылать только class object'у, а не экземплярам данного класса). Фактически методы класса являются аналогами статических методов в классах в языке С++. Знак минус служит для обозначения методов объектов — экземпляров данного класса. Обратите внимание, что в Objective-C все методы являются виртуальными, т.е. могут быть переопределены.
Ниже приводятся описания возможных методов для класса Rect.
@interface Rect: NSObject
float x, y;
float width;
float height;
BOOL isFilled;
NSColor * color;
>
+ newRect;
— (void) display;
— (float) width;
— (float) height;
— (float) area;
— (void) setWidth: (float) theWidth;
— (void) setHeight: (float) theHeight;
— (void) setX: (float) theX y: (float) theY;
end
Обратите внимание, что имя метода может совпадать с именем instance-переменной данного класса (например, width и heigh).
Тип возвращаемого методом значения указывается в круглых скобках сразу же после знака плюс или минус (но перед названием метода). Если тип не указан, то считается, что возвращается значение типа id. Далее идет имя метода, где после каждого двоеточия задается тип аргумента (в круглых скобках) и сам аргумент. Язык Objective-C позволяет для аргументов метода задавать также один из следующих описателей — oneway, in, out, inout, bycopy и byref. Данные описатели служат для задания направления передачи данных и способа передачи.
Метод, принимающий произвольное количество параметров, может быть описан следующим образом:
— makeGroup: (id) object, . ;
+ newRect Rect * rect = [[Rect alloc] init];
[rect setWidth: 1.0f];
[rect setHeight: 1.0f];
[rect setX: 0.0f y: 0.0f];
>
— (float) width < return width; >
— (float) height < return height; >
— (float) area < return [self width] * [self height]; >
— (void) setWidth: (float) theWidth < width = theWidth; >
— (void) setHeight: (float) theHeight < height = theHeight; >
— (void) setX: (float) theX y: (float) theY x = theX;
y = theY;
>
end
Как видно из примера выше, в методах доступны все instance-переменные. Однако, как и в С++, есть возможность управлять видимостью переменных (видимостью методов управлять нельзя) при помощи директив private, protected и public (действующих полностью аналогично языку С++).
Чуть-чуть истории
Objective-C возник в 80-x как модификация С в сторону Smalltalk. Причем модификация эта состояла в добавлении новых синтаксических конструкций и специальном препроцессоре для них (который, проходя по коду преобразовывал их в обычные вызовы функций С), а также библиотеке времени выполнения (эти вызовы обрабатывающей). Таким образом, изначально Objective-C воспринимался как надстройка над C. В каком-то смысле это так и до сих пор: можно написать программу на чистом С, а после добавить к ней немного конструкций из Objective-C (при необходимости), или же наоборот, свободно пользоваться С в программах на Objective-C. Кроме того, все это касается и программ на С++. В 1988 NeXT (а в последствии Apple) лицензировала Objective-C и написала для него компилятор и стандартную библиотеку (по сути SDK). В 1992 к усовершенствованию языка и компилятора подключились разработчики проекта GNU в рамках проекта OpenStep. С тех пор GCC поддерживает Objective-C. После покупки NeXT, Apple взяля их SDK (компилятор, библиотеки, IDE) за основу для своих дальнейших разработок. IDE для кода назвали Xcode, а для GUI – Interface Builder. Фреймворк Cocoa для GUI разработок (и не только) на сегодня является наиболее значимой средой разработки программ на Objective-C.
Протоколы
Протокол Objective-C – это формализованное объявление группы методов, которые, по желанию, может реализовать любой класс (аналог класса в С++, где все методы объявлены со спецификатором virtual … = 0). В версии языка 2.0 методы протокола могут быть требуемыми (спецификатор @required, он считается умалчиваемым) и выборочными (спецификатор @optional). Если какой либо класс реализовал требуемые методы протокола, то он называется классом, поддерживающим данный протокол. Протокол, и класс, его поддерживающий, объявляются вот так:
Кроме того, один класс может удовлетворять нескольким протоколам. Для этого их можно перечислить через запятую в угловых скобках в объявлении класса.
А чтобы объявить объект неизвестного класса (id), соответствующий некоторому протоколу, пишут так:
Синтаксис языка
В языке Objective-C для обозначения объектов используется специальный тип id. Переменная типа id фактически является указателем на произвольный объект. Для обозначения нулевого указателя на объект используется константа nil. Кстати про id: движок игры Doom разрабатывался на рабочих станциях Next, так что может есть связь между типом id и названием idSoftware.
Определение класса
Теперь рассмотрим файл Complex.m с определением методов класса Complex:
Объявление класса
Объявим простой класс комплексного числа в файле Complex.h:
Свойства
Для версии Objective-C 2.0 нашa реализация класса Complex явно избыточна: в ней слишком много методов доступа и их определение – сплошная рутина. Перепишем его с использованием свойств:
As a fairly new objective-c programmer (with a 4 years Java experience), I seem to be having a hard time understanding when to use class extensions. From what I understood (and please, correct me if I'm wrong), the main difference between categories and extensions is that the extension expects you to implement the methods inside your main implementation, whereas with a category, it can be in another implementation. It also seems that people are using extensions mainly for private methods.
Here's my first question. What's the difference between using a class extension to declare a private method, and not declare it at all (it seems to compile in run in both cases)? (example 1 vs 2)
Second question: What's the difference between declaring ivars inside the extension and declaring it directly inside the implementation? (Exemple 3 vs 4)
I have a last question about coding conventions: when should I put an underscore (_) in front of a variable's name?
Regarding underscores, it is convention to prefix instance variables with them, like so: _mySortedArray
Классы
Как и в большинстве других объектно-ориентированных языках, классы в Objective-C обеспечивают основную конструкцию для формирования некоторых данных с действиями, которые воздействуют на эти данные. Объект — это просто экземпляр класса, который содержит в оперативной памяти копии переменных экземпляров класса, объявленных этим классом и указателями на методы класса.
Определение класса в Objective-C требует две различные части: интерфейс (interface) и реализация (implementation). Интерфейс определяет структуру экземпляров класса, а также instance-переменные и методы, связанные с классом. Реализация содержит код для описания методов класса. Иллюстрация 1 показывает синтаксис, объявляющий класс по имени MyClass, который наследуется из базового класса NSObject. Декларация класса всегда начинается с директивы компилятора @interface и заканчивается директивой @end. После имени класса следует имя родительского класса, отделенное двоеточием. Instance-переменные класса объявляются в блоке кода, который заключен в скобки (< и >). После блока описания instance-переменных следует список методов, объявленных классом. После каждого объявления instance-переменной или метода ставится точка с запятой.
Иллюстрация 1 Определение класса
Листинг 1 показывает реализацию класса MyClass из предыдущего примера. Как и в декларации класса, реализация (implementation) класса заключена между двумя директивами компилятора — @implementation и @end. Эти директивы предоставляют определенную информацию, которая нужна компилятору для того, чтобы связать вложенные методы с соответствующим классом. Поэтому, определение метода соответствует заданному определению в интерфейсе, кроме включения блока с кодом.
Листинг 1 Реализация класса
Примечание: Хотя предыдущая реализация класса объявляет только методы, однако классы могут также объявлять и свойства. Для получения дополнительной информации о свойствах, см. в разделе «Свойства» данного материала.
Когда вы храните объекты внутри переменных, вы так или иначе используете ссылочный тип (pointer type). Objective-C поддерживает как явное, так и неявное объявление типов переменных, содержащих объекты. Явно объявленные указатели включают название класса в объявлении типа переменной. Неявно объявленный тип указателя, в отличии от явного, использует тип id для объектов. Неявно объявленный тип указателя чаще всего используется для таких вещей, как коллекционные классы, где может быть неизвестным точный тип объектов коллекции. Если вы привыкли использовать языки, где используется только явное объявление типов, тогда наверное вы будете думать, что использование неявного объявления типа переменных вызовет кучу проблем. Однако, на самом деле, это обеспечивают огромную гибкость и намного большую динамичность в программах Objective-C.
Вот пример обоих типов объявления переменных для класса Myclass:
Категории и расширения
Если к уже написанному (а, возможно, и откомпилированному) классу нужно добавить\переопределить некоторые методы без наследования – категории позволяют это сделать без особых усилий:
А пользоваться этим можно вот так:
Расширения несут добрую службу как безымянные категории:
Сборка мусора
Objective-C 2.0 позволяет производить автоматическую сборку мусора, правда это опционально.
Быстрая энумерация
Теперь добавлен аналог оператора foreach:
for (Person *p in thePeople) NSLog(@"%@ is %i years old.", [p getName], [p getAge]);
В следующей части расскажу про среду разработки XCode и редактор интерфейсов Interface Builder, а также покажу создание совсем простенького приложения.
У любого желающего писать программы для продукции фирмы Apple в жизни наступает такой момент, когда ему приходиться изучить новый язык программирования — Objective-C. Когда-то этот счастливый момент постиг и меня. А чтобы лучше запомнить основные особенности этого языка, решил законспектировать свои мысли во время осмысления его документации, которыми и делюсь с вами.
Методы доступа
Правильная работа с подсчетом ссылок очень важна при возврате адреса объекта из метода или инициализации инварианта формальным параметром. Обычно такими вещами занимаются так называемые методы доступа, возвращающие и устанавливающие инварианты объектов. Принято именовать метод, возвращающий значение инварианта, так же как и инвариант, а имя метода, устанавливающего его значение, начинать со слова set:
Так как инвариант _re относится ко встроенному типу, никаких сложностей с изменением его значения не возникает. Но если инвариант – объект некоторого класса – то простым присваиванием не обойтись, ведь надо учитывать счетчики ссылок. Для решения этой проблемы применяются следующие три метода:
Вариант №3 не очень удачный потому, что засоряет текущий самовыгружаемый пул, а обычно это не очень желательно (см. следующий раздел).
Метод доступа для чтения значения инварианта всегда очень прост:
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 кода. |
Создание объектов
После создания объекта им можно смело пользоваться:
Некоторые классы обладают методом для быстрого (в один этап) создания собственных экземпляров. Такие методы являются методами класса, возвращают указатель на объект своего класса и их имя обычно начинается с названия самого класса. Например метод:
Возвращает уже готовую строку, инициализированную соответствующей сторокой с завершающим нулем, без вызовов alloc и init:
Особенности Objective-C
- interface Начинает объявление класса или категории (категория – расширение класса дополнительными методами без наследования)
- @implementation Начинает определение класса или категории
- @protocol Начинает объявление протокола (аналог класса С++, состоящего из чисто виртуальных функций)
- end Завершает объявление\определение любого класса, категории или протокола
- @private Ограничивает область видимости инвариантов класса методами класса (аналогично С++)
- protected Стоит по умолчанию. Ограничивает область видимости инвариантов класса методами класса и методами производных классов (аналогично С++)
- @public Удаляет ограничения на облать видимости (аналогично С++)
- try Определяет блок с возможной генерацией исключений (аналогично С++)
- @throw Генерирует объект-исключение (аналогично С++)
- catch () Обрабатывает исключение, сгенерированное в предшествующем блоке try (аналогично С++)
- finally Определяет блок после блока try, в который предается куправление независимо от того, было или нет сгенерировано исключение
- @class Сокращенная форма объявления класса (только имя (аналогично С++))
- selector(method_name) Возвращает скомпилированный селектор для имени метода method_name
- @protocol(protocol_name) Ворзвращает экземпляр класса-протокола с именем protocol_name
- @encode(type_spec) Инициализирует строку символов, которая будет использована для шифрования данных типа type_spec
- @synchronized() Определяет блок кода, выполняющегося только одной нитью в любой определенный момент времени
Перед каждым параметром необходимо ставить двоеточие. Сколько двоеточий – столько и параметров. Имя метода может продолжаться после каждого такого двоеточия-параметра:
Методы с неограниченным количством аргументов вызываюся следующим синтаксисом:
Тип SEL, по сути, определен как char const *, но лучше воспринимать его как int, поскольку во время выполнения все селекторы индексируются целыми значениями согласно глобальной таблице селекторов.
При такой схеме вызов, например:
Так как в глобальной таблице селекторов 12 соответствует строке “addObject:”. Далее функция objc_msgSend() выполняет поиск по списку селекторов объекта receiver и, найдя его (пусть это объект класса NSArray, который реализовал метод с селектором 12), производит вызов типа:
Самовыгружаемый пул в нитях программы
Теперь попробуем вернуть из метода созданный внутри него объект:
Строка формата соответствует стандарту языка С. Но если в ней необходимо указать тип id, то используется спецификатор формата %@. Каким образом метод, разбирающий формат, понимает какие символы подставить вместь id? Он просто подставит то, что вернет метод описания description данного объекта. Этот метод изначально объявлен для класса NSObject. NSString переопределил его на вывод своего строкового содержания. Переопределив его, любой объект может представлять свое строковое содержание. Например, так это может сделать класс комплексного числа с двумя инвариантами типа double:
Любая нить в программе, использующей Cocoa, должна создавать объект класса NSAutoreleasePool в самом начале (прежде создания других объектов), и в самом конце его уничтожать (после уничтожения всех других объектов). Функция main(), являющаяся главной нитью любой программы на Objective-C, при использовании фреймворка Cocoa должна всегда выглядеть вот так:
А корректный метод sayHelloToName:withSurname: теперь будет выглядеть вот так:
К слову, метод drain самовыгружаемого пула аналогичен release с той лишь разницей, что, кроме освобождения себя самомго и всех содержащихся объектов, еще дает подсказку сборщику мусора вступить в игру. Однако, это актуально только для Mac OS 10.4 и выше, так как на iOS сборки мусора нет.
Протоколы и Делегаты
Протокол объявляет методы, которые могут быть реализованы любым из классов. Но сами по себе протоколы, при этом, не являются классами. Они просто определяют интерфейс, за реализацию которого ответственны другие объекты. Когда вы реализуете методы протокола в одном из ваших классов, то можно сказать, что ваш класс соответствует этому протоколу.
В iPhone OS обычно протоколы используются для делегирования объектов. Делегированный объект — это объект, который действует от имени (или под руководством) другого объекта. Чтобы лучше понять как взаимодействуют между собой протоколы, делегаты и другие объекты, давайте рассмотрим пример.
Например, класс UIApplication реализует нужное нам поведение приложения. Вместо того, чтобы заставлять подкласс UIApplication получать простые запросы о текущем состоянии приложения, класс UIApplication передает эти запросы назначенному объекту-делегату, вызывая при этом определенные методы. Тоесть, объект, который реализует методы протокола UIApplicationDelegate, может получать эти запросы и выдавать на них соответствующий ответ.
Объявление протокола похоже на интерфейс класса, за исключением того, что у протоколов нет родительского класса, и они не определяют переменные экземпляра. Следующий пример показывает простое объявление протокола с одним методом:
В случае, когда используется много протоколов делегирования, принятие протокола — это просто вопрос реализации методов определенных этим протоколом. Есть некоторые протоколы, которые требуют, чтобы вы ясно заявили, что вы поддерживаете протокол, и тогда протоколы могут определять оба метода, как необходимые, так и опциональные. Чем глубже вы увлекаетесь разработкой приложений, тем больше времени вам придется потратить на то, чтобы почитать раздел «Protocols» из документа The Objective-C 2.0 Programming Language.
Хотите знать больше?
Предыдущая информация была предназначена прежде всего для того, чтобы ознакомить вас с базовыми основами языка Objective-C. Охваченный в данном материале предмет отражает лишь некоторые особенности языка, с которыми вы наверняка встретитесь. Однако вам необходимо знать, что описанные здесь особенности — не единственные, поэтому мы всегда поощряем читать больше об Objective-C в документе The Objective-C 2.0 Programming Language.
Я думаю все слышали про Mac OS X как операционную систему для дизайнеров и домохозяек. Но хочется рассказать про средства разработки для OS X, а то хорошие программы пишут, а на чем — никто не знает.
Сразу скажу, что не буду рассказывать про кроссплатформенные фреймворки и тулкиты(такие как Qt) или про создание консольных приложений, я расскажу про то, что в плане создания приложений отличает Mac OS X от других операционных систем, а именно — фреймворк Cocoa. Оговорюсь сразу, что буду стараться избегать сравнений с другими фреймворками, я хочу просто рассказать про Cocoa.
Заглянем немного в историю. Mac OS X — дальнейшее развитие ОС NextSTEP. NextSTEP была первой ОС в которой очень широко использовался язык Objective-C, на нем была написана большая библиотека готовых объектов, причем как и обычные типы данных — строки, массивы, словари, так и объекты, используемые для построения GUI приложений. Поэтому, большая часть приложений под NextSTEP писалась на Objective-C с использованием готовых объектов. Эта самая библиотека и переросла в Cocoa framework.
Но включать в новую ОС почти незнакомый никому API было бы крайне плохим решением, поэтому добавили еще 2: Classic и Carbon.
Classic создан для того, чтобы запускались приложения Mac OS 9, на данный момент рассматривать его бессмысленно, т.к. после перехода на процессоры фирмы Intel по понятным причинам Classic был выкинут из системы.
Carbon был создан чтобы легко перенести приложения из Mac OS 9 в OS X, с возможностью добавить к уже готовому коду программы новую функциональность, доступную только в десятке. Как ни странно, но много приложений до сих пор написаны на Carbon(например MS Office for Mac и некоторые продукты Adobe).
На данный момент фреймворки Carbon и Cocoa развиваются паралельно, но со следующего релиза Mac OS X будут развивать только Cocoa.
Основным языком разработки под Cocoa является Objective-C, а поскольку в дальнейшем все примеры будут идти на этом языке, то впервой части я расскажу именно про него. Но если вы уже владеете Python или Ruby, то изучать Objective-C вам не надо, в XCode 3.0(срада разработки, о ней в следующей части) биндинги для этих языков «искаропки».
Помимо широкого известного и распространенного объектного расширения языка С — языка С++ — есть и другое его расширение — язык Objective-C, обладающий огромной простотой, полной совместимостью с языком С и очень мощной и выразительной объектной моделью, заимствованной из языка Smalltalk.
Язык был придуман Брэдом Коксом (Brad Cox) в начале 80-х годов прошлого века. Целью Кокса было создание языка, поддерживающего концепцию software IC. Под этой концепцией понимается возможность собирать программы из готовых компонент (объектов), подобно тому как сложные электронные устройства могут быть легко собраны из набора готовых интегральных микросхем (IC, integrated curcuits). При этом такой язык должен быть достаточно простым и основанным на языке С, чтобы облегчить переход разработчиков на него.
Получившийся в результате язык Objective-C оказался крайне прост — его освоение у С-программиста займет всего несколько дней. Он является именно расширением языка С — в язык С просто добавлены новые возможности для объектно-ориентированного программирования. При этом любая программа на С является программой и на Objective-C (для языка С++ это не верно).
Язык Objective-C поддерживает работу с метаинформацией — так у объекта непосредственно на этапе выполнения можно спросить его класс, список методов (с типами передаваемых аргументов) и instance-переменных, проверить, является ли класс потомком заданного и поддерживает ли он заданный протокол и т.п.
В языке есть нормальная поддержка протоколов (т.е. понятие интерфейса объекта и протокола четко разделены). Для объектов поддерживается наследование (не множественное), для протоколов поддерживается множественное наследование. Объект может быть унаследован от другого объекта и сразу нескольких протоколов (хотя это скорее не наследование протокола, а его поддержка).
На данный момент язык Objective-C поддерживается компилятором gcc. Довольно много в языке перенесено на runtime-библиотеку и сильно зависит от нее. Вместе с компилятором gcc поставляется минимальный вариант такой библиотеки. Также можно свободно скачать runtime-библиотеку от компании Apple: Apple's Objective-C runtime. Эти две runtime-библиотеки довольно похожи (в основном отличие заключается в именах методов), хотя далее я буду ориентироваться на runtime-библиотеку от компании Apple.
Объявление метода
Интересно отметить, что прототип метода addObject из предыдущего раздела в объявлении класса выглядел так:
Если в начале прототипа метода поставить знак плюс (“+”), то такой метод будет считаться методом класса, и, естественно, не будет принимать неявный параметр self (это аналогично объявлению static-метода в С++). А без инварианта isa объекта, на который указывает self, указатель super работать, конечно, тоже не будет.
Таким образом, прототип любого метода объявляется так:
Если метод возвращает некий объект (тип id) или класс (тип Class), можно воспользоваться вложенным синтаксисом вызова:
Создание и уничтожение объектов
id anObject = [[Rectangle alloc] init];
При создании нового класса обычно нет необходимости переопределять метод alloc, а вот необходимость переопределения метода init возникает достаточно часто (хотя во многих случаях можно положится на обнуление памяти alloc'ом).
Обратите внимание, что метод(ы) init является обычным методом, ничем не выделяющимся среди остальных (в отличии от С++, где конструктор — это особый метод, у которого например нельзя взять адрес). Поэтому при создании нового класса и метода init вызов переопределенного метода init (при помощи [super init]) должен быть произведен явно в самом начале метода.
Mac OS X (как и NextStep) для управления временем жизни объектов используют reference counting — каждый объект содержит внутри себя некоторый счетчик, при создании устанавливаемый в единицу.
— (void) dealloc
.
[super dealloc];
>
На WDC2006 Apple представила новую версию языка — 2.0. Среди нововведений были отмечены сборка мусора, быстрая энумерация, свойства в классах, 64-битная поддержка и многое другое. Следует отметить, что эти нововведения доступны только для Leopard.
Банальная теория возникновения ООП
Проблема повторного использования написанного кода и его переносимость постоянно заставляет программистов искать все новые пути его упорядочивания, структуризации и абстрагирования. Для решения этих проблем создаются новые парадигмы программирования, шаблоны проектирования, новые языки, компиляторы и стандартные библиотеки к ним, программные платформы и фреймворки. Так образовались парадигма подпрограмм (процедур), реализуемая при помощи процессорных команд CALL\RET и стека (по сути, перенос потока выполнения по адресу произвольной, а не следующей за текущей команды, с последующим возвратом). Затем, парадигма модулей (каждый файл – отдельная единица трансляции), породившая двухэтапную трансляцию: компиляция модулей, а затем их компоновка (статическая или динамическая) в исполняемый модуль.
Класс обычно оформляется как определенный программистом тип, основанный на встроенных (языковых) типах данных и\или других классах. Для языка С, не поддерживающего объектно-ориентированную парадигму, это может быть структура (struct). А набор подпрограмм реализуется как обычные функции, обязательно принимающие как минимум один параметр — указатель на набор данных, подлежащих обработке.
Основным преимуществом объектно-ориентированного подхода стала возможность создавать новые классы на основе уже написанных (добавлять инварианты и методы, переопределять методы, использовать определенные в базовом классе методы как свои), названное наследованием.
Набор методов представляет собой интерфейс для взаимодействия с инвариантами. Невозможность непосредственной модификации данных класса (без задействования его интерфейса) отражает принцип инкапсуляции. На рисунке показан класс и его объекты. Имеется инвариант x типа float и к нему интерфейс (метод) doubleX, возвращающий значение инварианта.
Первым языком с поддержкой объектно-ориентированного подхода стал Simula67. Затем появился Smalltalk. А в 80х начал оформляться С++ — основной язык современного системного программирования. Его расширение и усовершенствование в 90х породило ряд парадигм и шаблонов проектирования, и оказало необратимое влияние на современное видение объектно-ориентированного подхода, в том числе, и на язык 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 кода. |
Читайте также: