Шрифт:
Если применить метод сору к одному из ваших собственных классов, например, к вашей адресной книге (address book), как в строке NewBook = [myBook mutableCopy];
то будет выдано сообщение об ошибке: *** -[AddressBook copyWithZone:]: selector not recognized (селектор не распознан) *** Uncaught exception: (Невыявленное исключение) *** -[AddressBook copyWithZone:]: selector not recognized
Как уже говорилось, для реализации копирования с вашими собственными классами необходимо реализовать один или два метода согласно протоколу .
Теперь покажем, как добавить метод сору в класс Fraction, который много ис-пользовался в части I. Эти способы вполне применимы для ваших собственных классов. Если эти классы являются подклассами любого из классов Foundation, то потребуется реализация более сложной стратегии копирования, поскольку' в суперклассе может быть уже реализована его собственная стратегия копирования.
Напомним, что класс Fraction содержит две целые переменные экземпляра: numerator (числитель) и denominator (знаменатель). Чтобы создать копию одного из этих объектов, необходимо выделить пространство для новой дроби (fraction) и затем скопировать значения этих переменных в эту новую дробь.
При реализации протокола ваш класс должен реализовать метод copyWithZone:, чтобы реагировать на сообщение сору. (Сообщение сору просто передает сообщение copyWithZone: в наш класс с аргументом nil.) Если вам нужно отличать мутабельные и немутабельные копии, то потребуется также реализовать метод mutaЫеСоpyWithZone: согласно протоколу . Если вы реализуете оба метода, то copyWithZone: будет возвращать немугабельную копию, a mutableCopyWithZone: будет возвращать мутабельную копию. Создание мутабель- кой копии объекта не требует, чтобы копируемый объект был тоже мутабель- ным, и наоборот; вполне возможно, что может требоваться мутабельная копия немутабельного объекта (например, строкового объекта).
Директива @interface должна выглядеть следующим образом. @interface Fraction: NSObject <NSCopying>
Fraction — это подкласс NSObject, подчиняющийся протоколу NSCopying.
В файле секции implementation Fraction.m добавьте следующее определение для нового метода. -(id) copyWithZone: (NSZone *) zone { Fraction *newFract = [(Fraction allocWithZone: zone] init]; [newFract setTo: numerator over: denominator]; return newFract; }
Аргумент zone применяется для разных зон памяти, которые вы можете вы-делить для работы с профаммой. Это требуется только в том случае, если ваши приложения занимают много памяти, и вы хотите оптимизировать выделение памяти, группируя ее по зонам. Вы можете брать значение, передаваемое методу copyWithZone:, и передавать его методу выделения памяти allocWithZone:. Этот метод выделяет память в указанной зоне.
После выделения памяти для нового объекта класса Fraction в него копиру-ются переменные получателя numerator и denominator. Предполагается, что метод copyWithZone: будет возвращать новую копию объекта, которую вы создаете в своем методе.
Этот новый метод проверяется в профамме 18.3. // Копирование дробей #import "Fraction.h" Jfimport <Foundation/NSAutoreleasePool.h> int main (int arge, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Fraction *11 = [[Fraction alloc] init]; Fraction *f2; [ft setTo: 2 over: 5]; f2 = [fl copy]; [!2 setTo: 1 over: 3]; [fl print]; [12 print]; [fl release]; [f2 release]; [pool drain]; return 0; }
Вывод программы 18.3 2/5 1/3
Эта программа создает объект класса Fraction с именем fl и присваивает ему значение 2/5. Затем вызывается метод сору для создания копии, который передает сообщение copyWrthZone: этому объекту. Этот метод создает новый объект класса Fraction, копирует в него значения из 11 и возвращает результат. После воз-врата в main этот результат присваивается 12. Последующее присваивание 12 дро-би 1/3 подтверждает, что это не оказывает влияния на исходную дробь 11. Изме-ните строку программы 12 = [И сору];
на 12 = 11;
и удалите высвобождение (release) 12 в конце программы, после чего увидите другие результаты.
Если ваш класс может быть подклассом, то метод copyWithZone: будет насле-доваться. В таком случае вы должны изменить строку этого метода Fraction *newFract = [[Fraction allocWithZone: zone] init]; на строку Fraction *newFract = [[[self class] allocWithZone: zone] init];
Это позволяет выделить память для нового объекта изданного класса, кото-рый является получателем копии. (Например, если это подкласс с именем NewFraction, то нужно выделить в наследуемом методе память для нового объекта NewFraction вместо объекта Fraction.)
Если вы пишете метод copyWithZone: для класса, суперкласс которого тоже реализует протокол , то должны сначала вызвать метод сору в этом суперклассе для копирования наследуемых переменных экземпляра и затем включить ваш собственный код для копирования любых дополнительных пе-ременных экземпляра, которые вы могли добавить в этот класс.
Вы должны решить, какое копирование нужно реализовать в вашем классе: поверхностное или глубокое. Задокументируйте это для других пользователей вашего класса. 18.4. Копирование объектов в методах-установщиках и методах-получателях