Программирование на Objective-C 2.0
Шрифт:
Внесите изменения в классы Rectangle и XYPoint, определенные в главе 8, чтобы они подчинялись протоколу . Добавьте в оба класса метод copyWithZone;. Сделайте так, чтобы в Rectangle выполнялось копирование его члена XYPoint origin с помощью метода XYPoint сору. Имеет ли смысл реализовать как мутабельную, так и немутабельную копию для этих классов? Объясните.
Создайте объект-словарь NSDictionary и заполните его несколькими парами ключ/объект. Затем создайте мутабельную и немутабельную копии. Это глу-бокие или поверхностные копии? Проверьте свой ответ.
Кто обязан освобождать память, выделяемую для новой адресной карточки (AddressCard) в методе copyWithZone:, если выполнена реализация, как в этой главе? Почему?
Глава 19. Архивация
В терминологии Objective-C архивация — это процесс сохранения
В приложениях Mac OS X используются списки свойств XML (propertylist или plists) для сохранения такой информации, как настройки по умолчанию, настройки приложений и данные конфигурации, поэтому вам будет полезно узнать, как их создавать и считывать. Однако их использование в целях архивации ограничено, поскольку при создании списка свойств для структуры данных конкретные классы объектов не удерживаются, информация о нескольких ссылках на один объект и мутабельность объекта не сохраняются.
Примечание. Формат в списках свойств в так называемом «старом стиле» отли-чается от формата списков свойств XML. По возможности старайтесь придер-живаться списков свойств 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; }
Вывод
программы 19.2 archiving: Storing an object for later use (архивация: сохранение объекта для дальнейшего использования) abstract class: A class defined so other classes can inherit from it (абстрактный класс: Класс, определенный таким образом, чтобы другие классы могли наследовать из него) adopt: То implement all the methods defined in a protocol (принять: для реализации всех методов, определенных в протоколе)Ваши списки свойств не обязательно должны создаваться из программы на Objective-C; список свойств может поступать из любою источника. Вы можете создавать свои собственные списки свойств с помощью простою текстового ре-дактора или программы Property List Editor (Редактор списков свойств), которая находится в /Developer/Applications/Utilities на компьютерах с системой Mac OS X. 19.2. Архивация с помощью NSKeyedArchiver
В файле можно сохранять объекты любого типа, а не только строки, массивы и словари. Для этого необходимо создать архив с ключами (keyed archive) с помо-щью класса NSKeyedArchiver.
Mac OX X поддерживает архивы с ключами, начиная с версии I0.2. В ранних версиях с помощью класса NSArchiver создавались последовательные архивы (sequential archives). Данные последовательных архивов должны считываться точно в том же порядке, в каком они записывались.
В архиве с ключами каждое поле архива имеет имя. При архивации объекта мы присваиваем ему имя, или ключ. При считывании объекта из архива мы ис-пользуем тот же ключ. Это позволяет записывать объекты в архив и считывать их в любом порядке. Кроме того, есл и в классе добавляются или удаляются новые переменные экземпляра, это можно предусмотреть в программе.
Отметим, что NSArchiver недоступен в iPhone SDK. Если нужна архивация в iPhone, вы должны использовать NSKeyedArchiver.
Чтобы использовать архивы с ключами, нужно импортировать <Foundation/NSKeyedArchiver.h>.
В программе 19.3 показано, как сохранять файл на диске с помощью метода archiveRootObjectrtoRle: из класса NSKeyedArchiver. Чтобы использовать этот класс, нужно включить в программу соответствующий файл с помощью оператора #import <Foundation/NSKeyedArchiver.h> #import <Foundation/NSObject.h> #import <Foundation/NSString.h> #import <Foundation/NSDictionary.h> #import <Foundation/NSKeyedArchiver.h> #import <Foundation/NSAutoreleasePool.h> int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] initj; 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 ]; [NSKeyedArchiver archiveRootObject: glossary toFile: @"glossary.archive"]; [pool release]; return 0; }
Программа 19.3 не выводит никаких данных на терминал. Однако оператор [NSKeyedArchiver archiveRootObject: glossary toFile: @"glossary.archive"];
записывает словарь glossary в файл glossary.archive. Для этого файла можно задать любой путь. В данном случае файл записывается в текущую папку.
Этот архивный файл можно в дальнейшем читать в программу с помощью метода NSKeyedUnarchiver unArchiveObjectWithFile:, как показано в программе 19.4. #import <Foundation/NSObject.h> #import <Foundation/NSString.h> #import <Foundation/NSDictionary.h> #import <Foundation/NSEnumerator.h> #import <Foundation/NSKeyedArchiver.h> #import <Foundation/NSAutoreleasePool.ti> int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] in it]; NSDictionary *glossary; glossary = [NSKeyedUnarchiver unarchiveObjectWithFile: @"glossary.archive"]; for ( NSString *key in glossary) NSLog (@"%@: %@", key, [glossary objectForKey: key]); [pool drain]; return 0; }