Текст книги "Программирование на Objective-C 2.0"
Автор книги: Стивен Кочан
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 30 (всего у книги 32 страниц)
Преобразование любого значения в _Воо1 дает значение 0, если значение равно нулю, и 1 в противном случае.
Преобразование более длинного целого типа в более короткий вызывает усечение целого значения слева.
Преобразование типа с плавающей точкой в целый тип вызывает усечение дробной части значения. Если целый тип является недостаточным, чтобы вместить преобразованное значение с плавающей точкой, то результат яв-ляется неопределенным (как и в случае преобразования отрицательного значения с плавающей точкой в целое с атрибутом unsigned).
Преобразование более длинного значения с плавающей точкой в более ко-роткий тип может вызывать или не вызывать округление, прежде произой-дет усечение. Классы памяти и область действия
Термин класс памяти (storage class) относится к способу выделения памяти ком-пилятором и к области действия определения конкретной функции или метода. Классы памяти – это auto, static, extern и register. Класс памяти можно не указывать в объявлении, и он будет назначен по умолчанию, как это описывается ниже.
Термин область действия (scope) относится к границам действия определенного идентификатора внутри программы. Идентификатор, определенный вне любой функции, метода или блока операторов (мы будем называть здесь это БЛОКОМ), доступен для ссылки в любой последующей точке файла. Идентификаторы, определенные внутри БЛОКА, являются локальными относительно этого БЛОКА и могут локально переопределять идентификатор, определенный вне этого БЛОКА. Имена меток, а также имена формальных параметров известны во всем БЛОКЕ. Метки, переменные экземпляра, имена структур и компонентов структур, имена объединений и компонентов объединений, а также имена перечислимых типов данных не обязательно должны отличаться друг от друга или от имен переменных, функций или методов. Однако идентификаторы перечисления все же должны отличаться от имен переменных и от других идентификаторов перечисления, определенных в пределах одной области действия. Имена классов имеют глобальную область действия и должны отличаться от имен других переменных и типов в пределах одной области действия. Функции
Если при определении функции определяется класс памяти, он должен быть указан как static или extern. К функции, которая объявляется как static, можно обращаться только в пределах файла, который содержит эту функцию. Функ-ции, объявленные как extern (или функции, для которых не указан никакой класс), могут вызываться функциями или методами из других файлов. Переменные
В таблице В.5 приводится сводка различных классов памяти, которые могут использоваться в объявлении переменных, а также их области действия и спо-собы их инициализации.
Табл. В.5. Переменные: сводка классов памяти, областей действия и способов инициализации Класс памяти Место объявления переменной На нее можно ссылаться И инициализировать с помощью Комментарии static Вне любого БЛОКА Внутри данного файла Только константного выражения Переменные инициализируются только один раз при запуске программы; значения сохраняются в пределах БЛОКОВ; значение по умолчанию 0 Внутри какого-либо БЛОКА Внутри этого блока extern Вне любого блока Внутри данного файла Только константных выражения Переменная должна быть определена хотя бы в одном месте без ключевого слова extern или в одном месте с использованием ключевого слова extern с присваиванием начального значения. Внутри какого-либо БЛОКА Внутри этого блока auto Внутри какого-либо БЛОКА Внутри этого блока Любого допустимого выражения Переменная инициализируется каждый раз при входе в БЛОК; нет никакого значения по умолчанию. register Внутри какого-либо БЛОКА Внутри этого блока Любого допустимого выражения Присваивание регистра (register) не гарантируется; разнообразные ограничения на типы переменных, которые могут быть объявлены; нельзя брать адрес переменной с register; инициализируется каждый раз при входе в этот БЛОК; нет никакого значения по умолчанию. Не указан Вне любого блока Внутри данного файла или из других файлов, которые содержат соответствующие объявления Только константного выражения Это объявление может появляться только в одном месте; переменная инициализируется при запуске программы; значение по умолчанию 0; по умолчанию используется класс памяти auto. Внутри какого-либо БЛОКА (См. auto) (См. auto) Переменные экземпляра
К переменным экземпляра можно получать доступ с помощью любого метода экземпляра, определенного для данного класса в секции interface, где явно объявляется эта переменная, или в категориях, созданных для данного класса. К наследуемым переменным экземпляра тоже можно осуществлять непосред-ственный доступ без каких-либо специальных объявлений. Методы класса не имеют доступа к переменным экземпляра.
Для управления областью действия переменной экземпляра можно исполь-зовать специальные директивы @private, @protected и @риЫк. После появления этих директив они действуют, пока не встретится закрывающая фигурная скобка, заканчивающая объявление соответствующих переменных экземпляра, или пока не будет использована другая из этих трех директив. Например, следующие строки являются началом объявления секции interface для класса с именем Point, содержащего четыре переменные экземпляра. @interface Point: NSObject { @private int internail D; @protected float x; float y; @public BOOL valid; }
Переменная internallD объявлена как private, переменные x и у – как protected (директива по умолчанию), переменная valid – как public.
Эти директивы описываются в таблице В.6.
Табл. В.6. Область действия переменных экземпляра Директива На переменную можно ссылаться Комментарии @protected С помощью методов экземпляра в данном классе, методов экземпляра в подклассах, и методов экземпляра в расширениях категорий на данный класс. Эта директива по умолчанию. @private С помощью методов экземпляра в данном классе, методов экземпляра в расширениях категорий на данный класс, но не из каких-либо подклассов. Эта директива ограничивает доступ самим классом. @public С помощью методов экземпляра в данном классе, методов экземпляра в подклассах и методов экземпляра в расширениях категорий на данный класс; доступ к такой переменной можно также выполнять из других функций или методов, применяя к экземпляру класса оператор косвенного указателя структуры (->), после которого следует имя переменной экземпляра (например, myfract->numerator). Эту директиву следует использовать только при необходимости; она нарушает понятие инкапсуляции данных. Функции
В этом разделе содержатся сведения о синтаксисе и работе функций. Определение функции Общий формат возвращаемыйТип имя (тип1 парам 1, тип2 парам2,..) { Объявления Переменных программныйОператор программныйОператор return выражение; }
Определяется функция имя, которая возвращает значение типа возвращаемый-Тип и имеет формальные параметры парам1, парам2,парам 1 объявляется с типом тип/, парам2с типом тип2, ит.д.
Локальные переменные обычно объяапяются в начале функции, но это не обязательно. Они могут быть объявлены в любом месте, и тогда доступ к ним ограничен операторами, которые следует в функции после их объявления.
Если функция не возвращает значения, то возвращаемыйТип указывается как void.
Если в круглых скобках содержится только void, функция не принимает ни-каких аргументов. Если применяются .. в качестве последнего (или единственного) параметра в списке, функция принимает переменное число аргументов, например, int printf (char *format, ...) { }
В объявлениях для аргументов одномерных массивов не обязательно указывать число элементов этого массива. Для многомерных массивов нужно обязательно указать размер каждой размерности, кроме первой.
Описание оператора return см. ниже в разделе «Оператор return». По-прежнему поддерживается старый способ определения функций. Для этого используется следующий общий формат. возвращаемыйТип имя (парам 1, парам2,„) объявления параметров { ОбъявленияПеременных программныйОператор программныйОператор return выражение, }
Здесь в круглых скобках указываются только имена параметров. Если функция не принимает никаких аргументов, то указываются только левая и правая круглые скобки. Тин каждого параметра объявляется вне круглых скобок и перед левой фигурной скобкой, открывающей определение функции. Например, ниже определяется функция с именем rotate, которая принимает два парамегра с именами value и п. unsigned int rotate (value, n) unsigned int value; int n; { }
Первый аргумент определяется как unsigned int и второй как int.
Перед определением функции можно поместить ключевое слово inline как указание компилятору. Некоторые компиляторы заменяют вызов такой функ-ции конкретным кодом самой функции, что ускоряет выполнение. Ниже пока-зан соответствующий пример. inline int min (int a, int b) { return ( a < b ? a : b); } Вызов функции Общий формат имя ( арг1, арг2,..)
Происходит вызов функции имя, и значения арг1, арг2, ... передаются функ-ции как аргументы. Если функция не принимает никаких аргументов, указы-ваются только открывающая и закрывающая круглые скобки (например, initialize 0).
Если вызывается функция, которая определена после самого вызова или находится в другом файле, то необходимо включить объявление прототипа для этой функции, которое имеет следующий общий формат. возвращаемыйТип имя (тип1 парам 1, тип2 парам2, .. )
Это указывает компилятору тип возвращаемого значения функции, число аргументов, которое она принимает, и тип каждого аргумента. Например, в строке long double power (double x, int n);
содержится объявление power как функции, которая возвращает значение типа long double и принимает два аргумента типа double и типа int. Имена аргументов внутри круглых скобок на самом деле являются фиктивными именами, и они могут быть опущены, то есть long double power {double, int); означает то же самое.
Если компилятор уже встретил определение функции или объявление про-тотипа для этой функции, то при вызове функции тип каждого аргумента пре-образуется (там, где возможно) в соответствии с типом, который объявлен в функции.
Если компилятор не встретил ни определения функции, ни объявления про-тотипа, то он предполагает, что функция возвращает значение типа int, автома-тически преобразует все аргументы типа float в тип double и выполняет целочисленное расширение любых целых аргументов, как описано выше в разделе «Преобразование базовых типов данных». Другие аргументы функции передаются без преобразования.
Функции, которые принимают переменное число аргументов, должны быть объявлены соответствующим образом. В противном случае компилятор будет предполагать, что функция принимает фиксированное число аргументов, ос-новываясь на числе аргументов, фактически использованных при вызове фун-кции.
Если функция была определена в старом формате (см. выше раздел «Определение функции»), то объявление для такой функции имеет следующий формат. возвращаемыйТип имя ();
Аргументы, передаваемые такой функции, преобразуются в соответствии с описанием в предыдущем абзаце.
Для функций, возвращаемый тип которых объявлен как void, компилятор выводит сообщение для любых вызовов, где делается попытка использования возвращаемого значения.
Все аргументы передаются функции по их значению, поэтому их значения не могут быть изменены функцией. Но если функции передается указатель, то функция может изменить значения, которые указываются этим указателем, но она все же не может изменить значение самой переменной-указателя. Указатели на функции
Имя функции без последующей пары круглых скобок создает указатель на эту функцию. К имени функции можно также применить адресный оператор, что-бы создать указатель на эту функцию.
Если fp – указатель на функцию, то соответствующую функцию можно вызвать, написав fp()
или (*fp)() Если функция принимает аргументы, они должны быть указаны в круглых скобках. Классы
В этом разделе приводятся сведения о синтаксисе и семантике классов. Определение класса
В определение класса включается объявление переменных экземпляра и мето-дов в секции interface, а также определение кода для каждого метода в секции implementation. Секция interface Общий формат @interface имяКласса: родительскийКласс <протокол, ...> { объявления ПеременныхЭкземлляра } объявлениеМегода объявлениеМегода @end
Класс имяКласса объявляется с помощью родительского класса родительс-кийКласс. Если имяКласса принимает также один или несколько формальных протоколов, то имена протоколов перечисляются в угловых скобках после ро-дительского класса. В этом случае соответствующая секция implementation должна содержать определения всех методов из перечисленных протоколов.
Если двоеточие и родительскийКласс не указаны, это означает, что объявляется новый корневой класс. Объявления переменных экземпляра
В необязательной секции объявленияПеременныхЭкземплярауказываются тип и имя каждой переменной экземпляра для данного класса. Каждый экземпляр класса имяКласса получаег свой собственный набор этих переменных плюс переменные, наследуемые из класса родительскийКласс. Доступ к таким переменным можно осуществлять непосредственно по имени в методах экземпляра, определенных в классе имяКласса, или из подклассов класса имяКласса. Если доступ ограничен директивой @private, то подклассы не могут осуществлять доступ к таким пере-менным (см. выше раздел «Переменные экземпляра»).
Методы класса не имеют доступа к переменным экземпляра. Объявления свойств
Общий формат @property {атрибуты) списокИмен-,
Объявляются свойства с помощью заданного списка атрибутов с разделите лями-запятыми.
списокИмен – это список с разделителями-запятыми, содержащий имена свойств объявляемого типа. {тип) имяСвойства1, имяСвойства2, имяСвойстваЗ,...
Директива @property может присутствовать в любом месте секции объявления метода для класса, протокола или категории.
Табл. В.7. Атрибуты свойств Атрибут Описание assign Используется простое присваивание, чтобы задать значение переменной экземпляра в методе-установщике (setter). (Это атрибут по умолчанию.) сору Используется метод сору, чтобы задать значение переменной экземпляра. getter=имя Используется имя для имени метода-получателя (getter) вместо имени имяСвойства, которое используется по умолчанию для синтезируемого метода-получателя. nonatomic Значение может быть возвращено непосредственно из синтезируемого метода-получателя. Если этот атрибут не объявлен, то методы доступа (accessor) действуют с атрибутом atomic; это означает, что доступ к переменным экземпляра защищен блокировкой mutex. Это обеспечивает защиту в среде с несколькими потоками за счет того, что операция get или set выполняется только в одном потоке. Кроме того, по умолчанию в среде без сборки мусора синтезируемый метода-получатель будет удерживать (retain) и автоматически высвобождать (autorelease) свойство, прежде чем возвратить его значение. ~fwrite Значение свойства можно читать и задавать. Компилятор предполагает, что вы сами предоставили метод-получатель и метод-установщик (getter и setter), или он будет синтезировать оба метода, если используется директива @synthesize. retain Свойство должно удерживаться (retain) во время присваивания. Этот атрибут можно указывать только для типов Objective-C. setter=имя Используется имя для имени метода-установщика (setter) вместо заданного имени имяСвойства, которое используется по умолчанию для синтезируемого метода доступа.
Можно указывать только один из атрибутов assign, сору или retain. Если у вас не используется сборка мусора, то один из этих атрибутов должен быть использован явным образом; в противном случае вы получите предупреждение от компилятора. Если у вас используется сборка мусора и вы не указали один из этих трех атрибутов, то будет применяться атрибут по умолчанию assign. В этом случае компилятор выдаст предупреждение, только если данный класс подчиняется протоколу NSCopying (в этом случае для свойства может потребоваться атрибут сору, а не assign). Если вы используете атрибут сору, то синтезируемый метод-установщиком применяет метод сору данного объекта. Это дает немутабельную копию. Если вам требуется мутабсльная копия, то вы можете предоставить вместо этого свой собственный метод-установщик. Объявление метода
Общий формат мТип (возвращаемыйТип) имя??1: (тип1) парам 1 имя??2: (тип2) парам2, ...;
Объявляется метод имя 1:имя2:.., который возвращает значение типа возвраща-емыйТип; он имеет формальные параметры парам1, парам2 ларам/ объявляется с типом 7ил/, парам2с типом тип2, и т.д.
Любое из имен после имя/ (то есть имя2,...) можетбыть опущено; в этом слу-чае все же используется двоеточие в качестве заполнителя, и оно становится частью имени метода (см. следующий пример).
Если в качестве м Тил указан знак +, это означает, что объявляется метод класса, а если знак -, то объявляется метод экземпляра.
Если объявляемый метод наследуется из родительского класса, то новое определение подавляет определение родительского класса. В этом случае все же имеется доступ к методу родительского класса, и для этого нужно передать сообщение к super. Вызов методов класса происходит, когда соответствующее сообщение передается объекту-классу, а вызов методов экземпляра происходит, когда соответствующее сообщение передается экземпляру класса. Методы класса и методы экземпляра могут иметь одинаковые имена.
Одинаковое имя метода может также использоваться в различных классах. Способность объектов различных классов реагировать на методы с одинако-выми именами называется полиморфизмом (polymorphism).
Если метод не возвращает значения, то возвращаемыйТип указы вас гея как void. Если метод возвращает значение типа id, то возвращаемыйТип можно не указывать, хотя практика надежного программирования рекомендует указы вать id к? возвращаемый тип.
Если используется ,... в качестве последнего (или единственного) параметра в списке, то метод принимает переменное число параметров, например, -(void) print: (NSSTRING *) format, ... { }
Ниже приводится пример объявления класса в секции interface: объявляется класс с именем Fraction, родительским классом для которого является NSObject. @interface Fraction: NSObject { int numerator, denominator; ) +(Fraction *) newFract; -(void) setTo: (int) n : (int) d; -(void) setNumerator: (int) n andDenominator: (int) d; -(int) numerator; -(int) denominator; @end
Класс Fraction имеет две целые переменные экземпляра с именами numerator и denominator. Он также содержит один метод класса с именем newFract, который возвращает объект типа Fraction. В него включены также два метода экземпляра с именами setTo:: и setNumerator:andDenominator:. Каждый из них принимает два аргумента и не возвращает никакого значения. В нем содержатся также два метода экземпляра с именами numerator и denominator, которые не принимают никаких аргументов и возвращают значение типа int. Секция implementation Общий формат @implementation имяКласса; определениеМетода определениеМетода ... @end
Определяется класс с именем имяКлаеса. Родительский класс и переменные экземпляра обычно не объявляются повторно в секции implementation (хотя это можно делать), поскольку они уже объявлены ранее в секции interface.
Если реализуются методы ые из какой-либо категории (см. ниже раздел «Оп-ределение категории»), то в секции implementation должны быть определены все методы, объявленные в секции interface. Если в секции interface были указаны один или несколько протоколов, то должны быть определены все методы этих протоколов – неявным образом через наследование или явным образом путем определения в секции implementation.
Каждое определениеМетода содержит код, который будет выполняться при вызове этого метода. Определение метода
Общий формат мТип (возвращаемый Тип) имя1: (тип1) парам 1: имя2(тип2) парам2, ... { обьявленияПеременных программныйОператор программныйОператор return выражение; }
Определяется метод имя1:имя2:.., который возвращает значение типа возвращаемыйТип и имеет формальные параметры парам}, парам2,....; парам} объявляется с типом тип}, парам2с типом тип2, и т.д. Если в качестве мТип указан знак +, это означает, что определяется метод класса, а если знак то определяется метод экземпляра. Это объявление метода должно быть согласовано с соответствующим объявлением метода в секции interface или с определенным ранее определением протокола.
В методе экземпляра можно обращаться к переменным экземпляра данного класса и любым переменным, которые унаследованы этим методом непосред-ственно по имени. Если определяется метод класса, он не может обращаться к каким-либо переменным экземпляра.
Внутри метода можно использовать идентификатор self для ссылки на объект, для которого вызывается метод, то есть на получателя сообщения. Внутри метода можно использовать идентификатор super для ссылки на родительский класс объекта, для которою вызывается метод.
Если возвращаемыйТип не указан как void, то в определении метода должны содержаться один или несколько операторов relume выражениями типа возвра-щаемыйТип. Если возвращаемыйТип указан как void, использовать оператор return не обязательно, и в случае использования он не может содержать возвращаемого значения.
Ниже приводится пример определения метода, где определяется метод setNumerator:andDenominator: в соответствии с его объявлением (см. выше раздел «Объявление метода»), -(void) setNumerator: (int) n andDenominator: (int) d { numerator = n; denominator = d; }
В этом методе двум его переменным экземпляра присваиваются передавае-мые аргументы и не выполняется оператор return (хотя это можно сделать), по-скольку в объявлении метода он не возвращает никакого значения.
В объявлениях для аргументов одномерных массивов не обязательно указывать число элементов этого массива. Для многомерных массивов нужно обязательно указать размер каждой размерности, кроме первой.
Внутри метода можно объявлять локальные переменные, и они обычно объявляются в начале определения метода. Память для автоматических локальных переменных выделяется при вызове метода, и она освобождается при выходе из метода.
Описание оператора return см. ниже в разделе «Оператор return». Синтезируемые методы доступа
Общий формат @synthesize свойство1, свойство2, ...
Здесь указывается, что для перечисленных свойств свойство}, свойство2,... должны быть синтезированы методы доступа.
В списке можно использовать форму записи свойство = instance_var, чтобы ука-зать, что свойство будет связано с переменной экземпляра instanceуаг. Синтези-руемые методы будут иметь характеристики, базирующиеся на атрибутах, объявленных ранее для свойства с помощью директивы @property. Определение категории
Общий формат @interface имяКласса (имяКатегории) <протокол,...> объявлениеМетода объявлениеМетода @end
Здесь объявляется категория имяКатегории для класса имяКласса с перечислен-ными методами. Если указаны один или несколько протоколов, категория под-чиняется перечисленным протоколам.
Компилятору должно быть известно имяКласса из предшествующего объяв-ления в секции @interface для этого класса. Можно объявить любое число кате-горий влюбом числе различных исходных файлов. Перечисленные методы ста-новятся частью данного класса и наследуются подклассами.
Категории уникально определяются парами ямяКласса/имяКатегории. Например, в определенной программе может быть только одна категория NSArray (Private). Но можно использовать одинаковые имена категорий. Например, определенная программа может содержать категорию NSArray (Private) и категорию NSString (Private), и это будут различные категории.
Вы не обязаны реализовать методы категории, которые не собираетесь ис-пользовать.
Категория может только расширять определение класса дополнительными методами или переопределять существующие методы этого класса. Она не мо-жет определять какие-либо новые переменные экземпляра для этого класса.
Если в нескольких категориях объявлен методе одним и тем же именем для одного класса, то нельзя определить, какой метод будет выполняться при вы-зове. Например, в следующем примере для класса Complex определяется катего-рия с именем ComplexOps, содержащая четыре метода экземпляра. #import «Complex.h» @interface Complex (ComplexOps) -(Complex *) abs; -(Complex *) exp; -(Complex *) log; -(Complex *) sqrt; @end
Можно предположить, что где-либо будет присутствовать секция implementation, в которой реализуются один ли несколько из этих методов. #import "ComplexOps.h" @implementation Complex (ComplexOps) -(Complex *) abs { } -(Complex *) exp { } -(Complex *) log { } -(Complex *} sqrt { } @end
Категория, содержащая методы, которые будут реализоваться другими подклассами, называется неформальным (informal) протоколом или абстрактной (abstract) категорией. В отличие от формальных протоколов, компилятор не выполняет никаких проверок на подчинение неформальному протоколу. На этапе выполнения объект может проверяться на подчиненность неформальному протоколу в зависимости от конкретного метода. Определение протокола
Общий формат @protocol имяПроюкола <протокол, ...> обьявленияМетодов @optional обьявленияМетодов @required обьявленияМетодов @end
Здесь определяется протокол имяПроюкола с указанными методами. Если включены другие протоколы, то протокол имяПротокола принимает (adopt) перечисленные протоколы.
Это определение называют также определением формального протокола. Класс подчиняется (conform) протоколу имяПротокола, если в нем определяются или наследуются все обязательные (required) методы, объявленные в этом протоколе, а также все методы любых других перечисленных протоколов. Компилятор проверяет подчиненность и выводит предупреждение, если класс не подчиняется объявленному формальному протоколу. На этапе выполнения объекты могут проверяться или Tie проверяться на подчиненность формальному протоколу.
Перед списком методов, реализация которых не обязательна, может ставиться директива @optional. В дальнейшем можно использовать директиву @required, чтобы обновить список обязательных методов, которые должны быть реализованы для подчинения протоколу.
Протоколы часто не привязываются к какому-либо определенному классу, но применяются как способ определения общего интерфейса, используемого несколькими классами. Специальные модификаторы типов
Для типов параметров и возвращаемого значения методов, объявляемых в про-токолах, могут использоваться спецификаторы типов, которые приводятся в таблице В.8. Эти спецификаторы используются для распределенных объектных приложений.
Табл. В.8. Специальные модификаторы типов в протоколах Спецификатор Описание in Аргумент относится к объекту, значение которого будет изменено отправителем и передано (т.е. скопировано) назад получателю. out Аргумент относится к объекту, значение которого будет изменено получателем и передано назад отправителю. inout Аргумент относится к объекту, значение которого будет изменяться как отправителем, так и получателем, и будет передаваться между ними; это спецификатор по умолчанию. oneway Используется для объявлений типа возвращаемого значения; обычно используется (one way void), чтобы указать, что объект, вызвавший этот метод, не обязан ожидать получения возвращаемого значения, то есть метод может выполняться асинхронно. bycopy Аргумент или возвращаемое значение должно копироваться. byref Аргумент или возвращаемое значение передается по ссылке и не копируется. Объявление объекта
Общий формат имяКласса *var1, *var2, ...;
Здесь определяются переменные varl, var2,... как объекты из класса тяКласса. Отметим, что это объявление переменных-указателей, при котором не выделяется пространство для конкретных данных, содержащихся в каждом объекте. В объявлении Fraction *myFract;
определяется myFract как объект класса Fraction или, точнее, как указатель на этот объект. Чтобы фактически выделить пространство для структуры данных класса Fraction, нужно вызвать обычно alloc или новый метод для этого класса, например, myFract = [Fraction alloc];
В результате для объекта типа Fraction будет выделен достаточный обьем па-мяти и возвращен указатель на этот объект, который будет присвоен переменной myFract. Переменную myFract часто называют объектом или экземпляром класса Fraction. Если метод alloc определен в корневом объекте, всем переменным эк-земпляра нового выделяемого объекта присваивается значение 0. Но это не оз-начает, что объект инициализирован должным образом; прежде чем использовать этот объект, для него должен быть вызван какой-либо метод инициализации (например, init).
Поскольку переменная myFract была объявлена явным образом как объект из класса Fraction, она называется переменной со статическим контролем типа. Компилятор может проверять применение переменных со статическим контролем типа на согласованность с определением класса с точки зрения правильности использования методов, а также типов их аргументов и возвращаемых значений. Объявление объекта с типом id
Общий формат id <протокол,...> varl, var2, ...;
Здесь объявляются переменные varl, var2,... как объекты из неопределенного класса, который подчиняется протоколам, перечисленным в угловых скобках. Список протоколов не является обязательным.
Переменным типа id можно присваивать объекты из любого класса, и наоборот. Если указаны один или несколько протоколов, компилятор проверяет, что методы, используемые из перечисленных протоколов для любой из объявленных переменных, используются соответствующим образом, то есть в соответствии с типами аргументов и возвращаемых значений для методов, объявленных в формальном протоколе.
Например, в строках id
компилятор проверяет, определяется ли метод add: в протоколе athOps. Если да, то компилятор проверяет для этого метода согласованность с типами аргументов и возвращаемого значения. Например, если метод add: принимает целый аргумент, а вы передаете ему объект класса Fractior, то компилятор выводит соответствующее сообщение.
Система следит за классом, которому принадлежит каждый объект; поэтому на этапе выполнения она может определить класс объекта и затем выбрать для вызова подходящий метод. Эти две процедуры называются соответственно динамическим контролем типов (dynamic typing) и динамическим связыванием (dynamic binding). Выражения с сообщениями Формат 1 [получатель имя1: арг1 имя2: арг2, имяЗ: аргЗ.. ]
Выполняется вызов метода имя!:имя2:имяЗ из класса, указанного получателем, и значения арг1, арг2,... передаются как аргументы. Эго называется выражением с сообщением (message expression). Значением выражения является значение, воз-вращаемое методом, или void, если метод объявлен соответствующим образом и не возвращает никакого значения. Тип этого выражения совпадает с типом, объявленным для вызываемого метода. Формат 2 [получатель имя];