Программирование на Objective-C 2.0
Шрифт:
Возможно, вы не хотите записывать объект непосредственно в файл с помощью метода archiveRootObject:ToFile:, как в предыдущих примерах. Например, вам нужно собрать некоторые объекты и сохранить их в одном архивном файле. Это можно сделать с помощью обобщенного класса объектов потока данных (data stream) NSData.
Как говорилось в главе 16, объект класса NSData можно использовать для ре-зервирования области памяти для сохранения данных. Эту область памяти можно использовать, например, для временного хранения данных, которые будут последовательно записываться в файл, или для хранения содержимого файла, считанного с диска. Проще всего создать мутабельную область данных с помощью метода data. dataArea = [NSMutableData data];
В результате создается пустое буферное пространство, размер которого расширяется по мере выполнения программы.
В качестве простого примера предположим, что нужно архивировать в од-ном
После выделения памяти для объекта NSKeyedArchiver передается сообщение initForWritingWithMutableData:, чтобы указать область, в которую будут записываться архивируемые данные; это область NSMutabledata с именем dataArea, которая была создана выше. Сохраненному в архиваторе объекту NSKeyedArchiver можно передавать теперь сообщения кодирования для архивации объектов в программе. На самом деле, архивация и сохранение все кодируемых сообщений выполняется в указанной области данных, пока не получено сообщение finishEncoding.
В данном случае кодируются два объекта: наша адресная книга и объект класса Foo. Для этих объектов можно использовать encodeObjectiforKey:, поскольку мы ранее реализовали методы кодирования (encoder) и кодирования (decoder) для классов AddressBook, AddressCard и Foo.
Закончив архивацию этих объектов, мы передаем объекту archiver сообще-ние finishEncoding. После этого нельзя кодировать никакие объекты, и мы должны передать это сообщение, чтобы завершить процесс архивации.
Область с именем dataArea теперь содержит наши архивированные объекты в форме, которую можно записать в файл. В выражении с сообщением [dataArea writeToFile: @"myArchive" atomically: YES encoding: NSUTF8Encoding error: nil]
передается сообщение writeToFtle:atomically:encoding:error: потоку данных для записи его данных в указанный файл с именем myArchive.
Как видно из части с оператором if, метод writeToFi(e:atomicalfy:encoding:error: возвращает значение YES типа BOOL, если операция записи успешно выполнена, и значение N0, если ее не удалось выполнить (например, был указан неверный путь к файлу или переполнена файловая система).
Восстановление данных из архивного файла осуществляется просто: нужно выполнить все действия в обратном порядке. Во-первых, нужно выделить, как и раньше, область данных, затем в эту область данных прочитать архивный файл. После этого мы создаем объект NSKeyedUnarchiver и сообщаем ему, что требуется декодировать данные из указанной области. Для извлечения и декодирования архивированных объектов нужно вызвать методы декодирования, а по окончании - передать сообщение finishDecoding объекту NSKeyedUnarchiver. Все это выполняется в программе 19. К). #import <Foundation/NSObject.h> #import <Foundation/NSAutoreleasePool.h> #import <Foundation/NSString.h> #import <Foundation/NSKeyedArchiver.h> #import <Foundation/NSCoder.h> #import <Foundation/NSData.h> #import "AddressBook.h" #import "Foo.h" * pool = [[NSAutoreleasePool alloc] inrt]; *dataArea; *unarchiver; *myFoo1; *myBook; // Чтение архива и присоединение к нему // объекта NSKeyedUnarchiver dataArea = [NSData dataWithContentsOfFile: @"myArchive"]; if (! dataArea) { NSLog (@"Can’t read back archive file!"); Return (1); } unarchiver = [[NSKeyedllnarchiver alloc] initForReadingWithData: dataArea]; // Декодирования объектов, которые мы сохранили ранее
Вывод программы 19.10 ======== Contents of: Steve's Address Book — Jamie Baker jbaker@hitmail.com Julia Kochan jewls337@axlc.com Stephen Kochan steve@steve_kochan.com Tony lannino tony.iannino@techfitness.com This is the string 12345 98.6
Адресная книга и объект Foo были успешно восстановлены из архивного файла. 19.5. Использование архиватора для копирования объектов
В программе 18.2 мы пытались создать копию массива, содержащего мутабель- ные строковые элементы, и создали поверхностную (shallow) копию этого мас-сива — копировались не сами строки, а только ссылки на них.
Возможности архивации Foundation позволяют создать глубокую (deep) ко-пию объекта. Например, в программе 19.11 выполняется копирование dataAnay в dataArray2 путем архивации dataAnay в буфер и его последующей деархивании с присваиванием результата массиву dataArray2. Нам не нужно задействовать файл для этого процесса; архивацию и деархивацию можно выполнять в памяти. #import <Foundation/NSObject.h> #import <Foundation/NSAutoreleasePool. h> #import <Foundation/NSString.h> #import <Foundation/NSKeyedArchiver.h> #import <Foundation/NSArray.h> int main (int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSData *data; NSMutableArray *dataArray = [NSMutableArray arrayWithObjects: [NSMutableString stringWithString; @"one"], [NSMutableString stringWithString; @"two"], [NSMutableString stringWithString: @ "three"], nil ]; NSMutableArray *dataArray2; NSMutableString *mStr; // Создание глубокой копии с помощью архиватора data = [NSKeyedArchiver archivedDataWithRootObject: dataArray]; dataArray2 = [NSKeyedUnarchiver unarchiveObjectWithData: data]; mStr = [dataArray2 objectAtlndex: 0]; [mStr appendString: @"ONE"]; NSLog (@"'dataArray:"); for ( NSString *elem in dataArray ) NSLog (n%@", elem); NSLog (@"\ndataArray2: "); for ( NSString *elem in dataArray2 ) NSLog ("%@"\ elem); [pool drsin]; return 0; }
Вывод программы 19.11 dataArray: one two three dataArray2: oneONE two three
Вывод подтверждает, что изменение первого элемента dataArray2 не оказывает влияния на первый элемент dataArray, поскольку новая копия этой строки была получена н ходе архивапии/деархивации.
Операция копирования в программе 19.11 выполняется с помощью следующих двух строк. data - [NSKcycdArchiver archivedDataWithRootObject: dataArray]; dataArray2 = [NSKeyedUnarchiver unarchiveObjectWithData: data];
Мы можем избежать промежуточного присваивания и выполнить копиро-вание с помощью одного оператора. dataArray2 = [NSKeyedUnarchiver unarchiveObjectWithData; [NSKeyedArchiver archivedDataWithRootObject: dataArray]];
Этот подход полезен для создания глубокой копии объекта или объекта, который не поддерживает протокол NSCopying. Упражнения
В главе 15 в программе 15.7 была создана таблица простых чисел. Внесите изменения в эту программу, чтобы записать результирующий массив в виде списка свойств ХМ L в файл primes.pl. Проверьте содержимое этого файла.
Напишите программу для чтения списка свойств XML, созданного в упражнении 1, и сохраните эти свойства в объекте-массиве. Выполните вывод всех элементов массива, чтобы убедиться, что операция восстановления прошла успешно.
Внесите изменения в программу 19.2, чтобы вывести содержимое одного из списков свойств XML (файлы .plist), сохраненного в папке /Library/Preferences.
Напишите программу чтения архивированной адресной книги (AddressBook) и выполните поиск записи в соответствии с именем, указанным в командной строке, например $ lookup gregory
Часть III. Cocoa и SDK iPhone Глава 20. Введение в Cocoa
На протяжении этой книги мы разрабатывали программы, которые имеют до-вольно простой пользовательский интерфейс. Для вывода сообщений на кон-соль мы использовали процедуру @@ NSLog. Это действительно полезная про-цедура, но ее возможности ограничены. Другие программы, которые мы используем на своих Маках, имеют намного более удобный интерфейс. Репу-тация компьютеров Macintosh во многом основывается на дружественных пользовательских окнах и простоте использования. В своих приложениях мы можем использовать XCode вместе с приложением Interface Builder. Это сочета-ние образует мощную среду для разработки программ со средствами редакти-рования и отладки и удобным доступом к online-документации и позволяет легко разрабатывать сложные графические пользовательские интерфейсы (GUI).