Чтение онлайн

ЖАНРЫ

Программирование на Objective-C 2.0
Шрифт:

Используя класс Rectangle из главы 8, добавьте метод-инициализатор в соответствии со следующим объявлением.
– (Rectangle *) initWithWidth: (int) w: andHeight: (int) h;

С учетом того, что мы назвали метод, разработанный в упражнении 1, назначенным (designated) инициализатором для класса Rectangle, и основываясь на определениях классов Square и Rectangle из главы 8, добавьте методинициализатор в класс Square в соответствии со следующим объявлением.
– (Square *) initWithSide: (int) side;

Добавьте счетчик (counter) к методу add: класса Fraction, чтобы вычислять количество вызовов этого метода. Каким образом вы можете считывать значение этого счетчика?

Используя typedef и перечислимые типы данных, определите тип с именем Day (День) с возможными значениями Sunday, Monday, Tuesday, Wednesday, Thursday, Friday

и Saturday (Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница и Суббота).

Используя typedef, определите тип с именем FractionObj, который позволяет писать следующие операторы. FractionObj И = [[Fraction alloc] init], f2 = [[Fraction alloc] init];

Используя определения float f = 1.00; short int i = 100; long int I = 500L; double d = 15.00; и семь шагов, описанных выше для преобразования операндов в выражениях, определите тип и значение следующих выражений. f + i l/d i / l + f 1 * i f / 2 i / (d + f) 1 / (i * 2.0) I + i / (double) I

Напишите программу, которая определяет, выполняется ли на вашей машине расширение для знака у переменных signed char.

Глава 11. Категории и протоколы

В этой главе описывается, как добавлять методы для класса в модульном стиле с помощью категорий и как создавать стандартизованный список методов для реализации другими людьми. 11.1. Категории

При работе с определенным классом к нему приходится добавлять новые методы. Например, для класса Fraction могут потребоваться методы, реализующие вычитание, умножение и деление двух дробей.

Предположим, что ваша группа в составе большого проекта определяет новый класс, который содержит много различных методов. Вашей задачей является написание для этого класса методов, которые работают с файловой системой. Другие члены проекта должны написать методы, которые реализуют создание и инициализацию экземпляров этого класса, выполняют операции над объектами в этом классе и рисуют представления объектов этого класса на экране.

Вы изучили, как использовать класс массивов из библиотеки Foundation framework с именем NSArray и поняли, что в этом классе необходимо реализовать один или нескольких методов. Конечно, вы могли бы написать новый подкласс класса NSArray и реализовать эти новые методы, но есть более простой способ. На практике для разрешения подобных ситуаций используются категории (category). Категория представляет простой способ модульного определения класса в виде групп или категорий связанных методов. Она также позволяет достаточно просто расширить существующее определение класса без доступа к существующему исходному коду этого класса или создания подкласса. Это мощная и достаточно простая для изучения концепция.

Вернемся к первому примеру и покажем, как добавить новую категорию в класс Fraction для работы с четырьмя основными арифметическими операциями. Приведем исходную секцию interface для Fraction. #import <Foundation/Foundation.h> #import <stdio.h> // Определение класса Fraction @interface Fraction : NSObject { int numerator; int denominator; } @property int numerator, denominator; -(void) setTo: (int) n over: (int) d; -(Fraction *) add: (Fraction *) f; -(void) reduce; -(double) convertToNum; -(void) print; @end

Теперь удалим метод add: из этой секции interface и добавим его в новую категорию вместе с тремя другими арифметическими операциями, которые нужно реализовать. Ниже показана секция in te rfa c e д л я новой категории MathOpS. #import «Fraction.h» @interface Fraction (MathOps) -(Fraction *) add: (Fraction *) f; -(Fraction *) mul: (Fraction *) f; -(Fraction *) sub: (Fraction *) f; -(Fraction *) div: (Fraction *) f; @end

Здесь представлено некоторое определение секции interface, по на самом деле это расширение существующей секции. Мы должны включить исходную секцию interface, чтобы указать компилятору на класс Fraction (правда, вы можете включить эту новую категорию непосредственно в исходный файл Fraction.h).

После строки «import мы вилим следующую строку: @interface Fraction (MathOps)

Она указывает компилятору, что для класса Fraction определяется новая категория с именем MathOps. Имя категории после имени класса

заключено в круглые скобки. Отметим, что здесь не указывается родительский класс для Fraction; компилятору уже извес тно о нем из Fraction.h. Кроме того, мы ничего не сообщаем ему о переменных экземпляра, хотя делали это во всех предыдущих секциях interface. На самом деле мы получим от компилятора сообщение о синтаксической ошибке, если попытаемся включить родительский класс или переменные экземпляра.

Эта секция interface указы вает компилятору, что мы добавляем в класс Fraction расширение под категорией с именем MathOps. Категория MathOps содержит четыре метода экземпляра: add:, mul:, sub: и div:. Каждый метод получает в качестве аргумента дробь (fraction) и возвращает тоже дробь.

Определения всех этих четырех методов можно поместить в одну секцию implementation.Мы можем определить в одной секции implementation все методы из секции interface файла Fraction.h плюс методы из категории MathOps. Мы также можем определить методы из этой категории в отдельной секции implementation. Тогда в секции implementation для этих методов следует также идентифицировать категорию, к которой принадлежат эти методы. Как и в секции interface, имя категории после имени класса нужно заключить: в круглые скобки @implementation Fraction (MathOps) // код для методов этой категории ... @end

В программе 11.1 для новой категории MathOps секции interface и implementation объединены в одном файле вместе с тестовой процедурой. #import "Fraction.h" @interface Fraction (MathOps) -(Fraction *) add: (Fraction *) f; -(Fraction *) mul: (Fraction *) f; -(Fraction *) sub: (Fraction *) f; -(Fraction *) div: (Fraction *) f; @end @implementation Fraction (MathOps) -(Fraction *) add: (Fraction *) f { // Для сложения двух дробей: // a/b + c/d = ((a*d) + (b*c)) / (b * d) Fraction *result = [[Fraction alloc] init]; int resultNum, resultDenom; resultNum = (numerator * f.denominator) + (denominator * f.numerator); resultDenom = denominator * f.denominator; [result setTo: resultNum over: resultDenom]; [result reduce]; return result; } -(Fraction *) sub: (Fraction *) f // Для вычитания двух дробей: // a/b - c/d = ((a*d) - (b*c)) / (b * d) Fraction *result = [[Fraction alloc] init]; int resultNum, resultDenom; resuUNum = (numerator * f.denominator) - (denominator * {.numerator); resultDenom = denominator * f.denominator; [result setTo: resultNum over: resultDenom]; [result reduce]; return result; } -(Fraction *) mul: (Fraction *) f { Fraction *result = [[Fraction alloc] init]; [result setTo: numerator * f.numerator over: denominator * f.denominator]; [result reduce]; return result; } -(Fraction *) div: (Fraction *) f { Fraction *result = [[Fraction alloc] init]; [result setTo: numerator * f.denominator over: denominator * {.numerator]; [result reduce]; return result; } @end int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Fraction *a = [[Fraction alloc] init]; Fraction *b = [[Fraction alloc] init]; Fraction *result; [a setTo: 1 over: 3]; [b setTo: 2 over: 5]; [a print]; NSLog (@" +"); [b print]; NSLog (@"----"); result = [a add: b]; [result print]; NSLog (@ "\n"); [result release]; [а print]; NSLog (@" -"); [b print]; NSLog (@"----"); result = [a sub: b]; [result print]; NSLog (@"\n"); [result release]; [a print]; NSLog (@" *"); [b print]; NSLog (@"----"); result = [a mul: b]; [result print]; NSLog (@"\n"); [result release]; [a print]; NSLog (@" /"); [b print]; NSLog (@"----"); result = [a div: b]; [result print]; NSLog (@"\n"); [result release]; [a release]; [b release]; [pool drain]; return 0; }

Вывод программы 11.1 1/3 + 2/5 ---- 11/15 1/3 - 2/5 ---- -1/15 1/3 * 2/5 ---- 2/15 1/3 / 2/5 ---- 5/6

И снова напомним, что в Objective-C вполне допустимы такие операторы, как [[a div: b] print];

В этой строке выполняется непосредственный вывод результата деления а на Ь, что позволяет избежать промежуточного присваивания результата какой- либо переменной, как в программе 11.1.Нам нужно это промежуточное присваивание, чтобы получить результирующую дробь (Fraction) и освободить память, которую она занимает. В противном случае при каждом выполнении арифметической операции над дробью будет происходить утечка памяти.

Поделиться с друзьями: