Программирование на Objective-C 2.0
Шрифт:
Вернемся к реализации метода сору. Если мы копируем переменные экземп-ляра, которые содержатнемутабельные объекты (например, немутабельные строковые объекты), то создание новой копии содержимого объекта, возможно, не потребуется. Достаточно создать новую ссылку на объект путем его удержания (retain). Например, если мы реализуем метод сору для класса AddressCard с члена-ми name и email, то достаточно написать следующую реализацию для copyWithZone:. -(AddresssCard *) copyWithZone: (NSZone *) zone { AddressCard *newCard = [[AddressCard allocWiihZone: zone] init]; [newCard retainName: name andEmail: email]; return newCard; -(void) retainName: (NSString *) theName andEmail: (NSString *) IheEmail { name = [theName retain]; email = [theEmail retain]; }
Здесь
В данном случае достаточно использовать удержание (retain) для переменных экземпляра вместо создания их полных копий, поскольку владелец скопированной карточки не может повлиять на компоненты пате и email исходной карточки. Убедитесь сами, что это действительно так (подсказка: он должен работать с методами-установщиками). Упражнения
Реализуйте метод сору для класса AddressBook согласно протоколу NSCopying. Имеет ли смысл реализовать также метод mutableCopy? Почему?
Внесите изменения в классы Rectangle и XYPoint, определенные в главе 8, чтобы они подчинялись протоколу . Добавьте в оба класса метод copyWithZone;. Сделайте так, чтобы в Rectangle выполнялось копирование его члена XYPoint origin с помощью метода XYPoint сору. Имеет ли смысл реализовать как мутабельную, так и немутабельную копию для этих классов? Объясните.
Создайте объект-словарь NSDictionary и заполните его несколькими парами ключ/объект. Затем создайте мутабельную и немутабельную копии. Это глу-бокие или поверхностные копии? Проверьте свой ответ.
Кто обязан освобождать память, выделяемую для новой адресной карточки (AddressCard) в методе copyWithZone:, если выполнена реализация, как в этой главе? Почему?
Глава 19. Архивация
В терминологии Objective-C архивация — это процесс сохранения одного или нескольких объектов в формате, позволяющем восстановить их в дальнейшем. Часто при этом объекты записываются в файл, чтобы их можно было прочитать. Мы рассмотрим в этой главе два метода архивации данных: списки свойств (property list) и кодирование с ключами (key-valued coding). 19.1. Архивация со списками свойств XML
В приложениях Mac OS X используются списки свойств XML (propertylist или plists) для сохранения такой информации, как настройки по умолчанию, настройки приложений и данные конфигурации, поэтому вам будет полезно узнать, как их создавать и считывать. Однако их использование в целях архивации ограничено, поскольку при создании списка свойств для структуры данных конкретные классы объектов не удерживаются, информация о нескольких ссылках на один объект и мутабельность объекта не сохраняются.
Примечание. Формат в списках свойств в так называемом «старом стиле» отли-чается от формата списков свойств XML. По возможности старайтесь придер-живаться
При записи данных в файл для объектов типа NSString, NSDictionary, NSArray, NSDate, NSData или NSNumber можно использовать реализованный в этих классах метод writeToFile:atomically:. При записи словаря или массива этот метод записывает данные в файл в формате списка свойств XML. В программе 19.1 показано, как записать в файл в виде списка свойств словарь, созданный в главе 15. #import <Foundation/NSObject.h> #import <Foundation/NSString.h> #import <Foundation/NSDictionary.h> #import <Foundation/NSAutoreleasePool.h> int main (int arge, char *argv[]) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSDictionary *glossary = [NSDictionary dictionaryWithObjectsAndKeys: @"A class defined so other classes can inherit from it.", @"abstract class", @'To implement all the methods defined in a protocol", @"adopt", @"Storing an object for later use.", @»archiving", nil ]; if ([glossary writeToFile: @"glossary" atomically: YES encoding: NSUTF3Encoding error: nil] == NO) NSLog (@"Save to file failed!"); [pool drain]; return 0; }
Сообщение writeToFile:atomically:encoding:enror: передается объекту-словарю glossary, что вызывает запись этого словаря в файл glossary в виде списка свойств. Параметру atomically присваивается значение YES, указывая, что операцию записи нужно выполнять сначала во временный резервный файл; если эта запись выпол-нена успешно, данные окончательно перемещаются в указанный файл с именем glossary. Эта мера защищает файл от повреждения, например, при сбое системы во время записи. В этом случае прежний файл glossary (если он уже существовал) не будет поврежден.
При просмотре содержимого файла glossary, созданного программой 19.1, мы увидим следующее. <?xml version=,,1.0" encoding="UTF-8"?> <!D0CTYPE plist PUBUC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.eom/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>abstract class</key> <string>A class defined so other classes can inherit from it.</string> <key>adopt</key> <string>To implement all the methods defined in a protocol</string> <key>archiving</key> <string>Storing an object for later use. </string> </dict> </plist>
XML-файл, созданный для этого словаря, содержит набор из пар ключей (<key>...</key>) и значений (<string>...</string>).
При создании списка свойств из словаря все ключи в этом словаре должны быть объектами NSString. Элементами массива или значениями в словаре могут быть объекты типа NSString, NSArray, NSDictionary, NSData, NSDate или NSNumber.
Для считывания данных используйте метод dataWithContentsOfFile:; для считы-вания строковых объектов используйте метод stringWithContentsOfFile:. В программе 19.2 выполняется считывание словаря, записанного в программе 19.1, и последующий вывод его содержимого. #import <Foundation/NSObject.h> #import <Foundation/NSString.h> #import <Foundation/NSDictionary.h> #import <Foundation/NSEnumerator.h> #import <Foundation/NSAutoreleasePool.h> int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSDictionary *glossary; glossary = [NSDictionary dictionaryWithContentsOfFile: @"glossary"]; for ( NSString *key in glossary ) NSLog (@"%@: %@", key, [glossary objectForKey: key]); [pool drain]; return 0; }