Программирование на Objective-C 2.0
Шрифт:
Следующие два метода, которые используются для класса AddressCard, должны быть добавлены в файл секции implementation. -(void) encodeWithCoder: (NSCoder *) encoder { [encoder encodeObject: name forKey: @"AddressCardName"]; [encoder encodeObject: email forKey: @"AddressCardEmair[; -(id) initWithCoder: (NSCoder *} decoder { name = [[decoder decodeObjectforKey: @"AddressCardName"] retain]; email = [[decoder decodeObjectforKey: @'AddressCardEmail"] retain]; return self; }
Метод кодирования encodeWithCoder: передается объекту NSCoder в качестве его аргумента. Поскольку класс AddressCard наследует непосредственно из NSObject, нам не нужно заботиться о кодировании наследуемых переменных экземпляра. Если суперкласс вашего класса согласуется с протоколом NSCoding, то, чтобы обеспечить кодирование своих наследуемых переменных экземпляра, вы должны
Наша адресная книга содержит две переменные экземпляра с именами name н email. Поскольку это объекты класса NSString, мы можем использовать метод encodeObject:forKey: для кодирования каждой из них по порядку. Затем эти переменные экземпляра добавляются в архив.
Метод encodeObject:forKcy: кодирует объект и сохраняет его с указанным ключом для последующего считывания с помощью этого ключа. Имена ключей можно задавать произвольно, для считывания (декодирования) данных нужно использовать тот же ключ, который использовался для их архивации (коди-рования). Конфликт может возникнуть только в том случае, если тот же ключ используется для подкласса кодируемого объекта. Чтобы не возникла эта ситуация, можно вставить имя класса перед именем переменной экземпляра, когда вы составляете ключ для архива, как это сделано в программе 19.5.
Отметим, что encodeObject:forKey: можно использовать для любого объекта, в классе которого имеется соответствующий реализованный метод encodeWithCoder:.
Процесс декодирования действует в обратном порядке. Аргумент, переда-ваемый initWithCoder:, тоже являегся объектом NSCoder. Вам не нужно заботиться об этом ар|ументе; он получает сообщения для каждого объекта, который вы хотите извлечь из архива.
Поскольку в данном случае класс AddressCard наследует непосредственно из NSObject, вам не нужно заботиться о декодировании наследуемых переменных экземпляра. Достаточно вставить следующую строку в начало ваше метода декодирования (decoder), если ваш класс согласуется с протоколом NSCoding. self = [super initWithCoder: decoder];
Каждая переменная экземпляра затем декодируется путем вызова метода decodeObjectforKey: и передачи того же ключа, который использовался для кодирования этой переменной.
Аналогично классу AddressCard, мы добавляем методы кодирования и декодирования в класс AddressBook. В файле секции interface нужно только изменить строку с директивой @interface, чтобы объявить, что теперь с протоколом NSCoding согласуется класс AddressBook. Это изменение может выглядеть следующим образом. @interface AddressBook: NSObject <NSCoding, NSCopying>
Ниже определяются методы для включения в файл секции implementation. -(void) encodeWithCoder: (NSCoder *) encoder { (encoder encodeObject: bookName forKey: "AddressBookBookName"]; (encoder encodeObject: book forKey: @"AddressBookBook"]; } -(id) initWithCoder: (NSCoder *} decoder { bookName = [[decoder decodeObjectForKey: @"AddressBookBookName"] retain]; book = [[decoder decodeObjectForKey: @"AddressBookBook"] retain]; return self; }
Программа 19.6 — это тестовая программа. #import «AddressBook. h» #import <Foundation/NSAutoreleasePool.h> int main (int argc, char *argv[]) { NSString *aName = @"Julia Kochan"; NSString *aEmail = @"jewls337@axlc.com"; NSString *bName = @"Tony lannino"; NSString *bEmail = @"tony.iannino@techfitness.com"; NSString *cName = @"Stephen Kochan"; NSString *cEmail = @"steve@steve_kochan.com''; NSString *dName = @"Jamie Baker"; NSString *dErnail = @"jbaker@hitmail.com"; NSAutoreteasePool * pool = [[NSAutoreleasePool alloc] init]; AddressCard *card1 = [[AddressCard alloc] ini:]; AddressCard *card2 = [[AddressCard alloc] init]; AddressCard *card3 = [[AddressCard alloc] initj; AddressCard *card4 = [[AddressCard alloc] init); AddressBook *myBook = [AddressBook alloc]; // Сначала задаем четыре адресные карточки [card 1 setName: aName andEmail: aEmail]; [card2 setName: bName andEmail: bEmail]; [card3 setName: cName andEmail: cEmail]; [card4 setName: dName andEmail: dEmail]; myBook = [myBook initWithName: (@"Steve's Address Book"]; // Добавляем несколько карточек в адресную книгу [myBook addCard: card 1 ]; [myBook addCard: card2]; [myBook addCard: card3]; [myBook addCard: card4]; [myBook sort]; if ([NSKeyedArchiver archiveRootObject: myBook toFile: @"addrbook.arch"] == NO) NSLog ((@"archiving failed"); [card 1 release]; [card2 release]; [card3 release]; [card4 release]; [myBook release]; [pool drain]; return 0; }
Эта
В программе 19.7 показано, как считывать архив в память для создания ад-ресной книги из файла. #import "AddressBook.h" #import <Foundation/NSAutoreleasePool.h> int main (int argc, char *argv[]) { AddressBook *myBook; NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; myBook = [NSKeyedUnarchiver unarchiveObjectWithFile: (@"addrbook.arch"]; [myBook list]; [pool drain]; return 0; }
Вывод программы 19.7 ======== 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
При разархивации этой адресной книги автоматически вызываются методы декодирования, добавленные в эти классы. Чтение в программу адресной книги выполняется предельно просто.
Метод encodeObjectforKey: используется применительно к встроенным классам и классам, для которых вы пишете свои методы кодирования и декодирования согласно протоколу NSCoding. Если ваши переменные экземпляра содержат некоторые базовые типы данных, например, int или float, вы должны знать, как кодировать и декодировать их (см. таблицу 19.1).
Ниже приводится простое определение для класса с именем Foo, который содержит три переменные экземпляра: типа NSString, типа int и типа float. Этот класс содержит один метод-установщик, три метода-получателя и два метода кодирования/декодирования, используемых для архивации. @interface Foo: NSObject <NSCoding> { NSString *strVal; int intVal; float floatVal; } @property (copy, nonatomic) NSString *strVal; @property int intVal; @property float floatVal; @end
Затем следует файл секции implementation. @implementation Foo @synthesize strVal, intVal, floatVal; -(void) encodeWithCoder: (NSCoder *) encoder { [encoder encodeObject: strVal forKey: @"FoostrVarj; [encoder encodelnt: intVal forKey: @"FoointVal"]; [encoder encodeFloat: floatVal forKey: @"Foofk>atVar]; } -(id) initWithCoder: (NSCoder *) decoder { strVal = [[decoder decodeObjectForKey: @"FoostrVal"] retain]; intVal = [decoder decodelntForKey: @"FoointVar]; floatVal = [decoder decodeFloatForKey: @'FoofloatVal"]; return self; } @end
В этой процедуре кодирования сначала кодируется строковое значение strVal с помощью метода encodeObject:forKey:, как показано ранее.
В программе 19.8 создается объект Foo, выполняется его архивация в файл, разархивация и последующий вывод. #import <Foundation/NSObject.h> #import <Foundation/NSString.h> #import <Foundation/NSKeyedArchiver.h> #import <Foundation/NSAutoreleasePool.h> #import "Foo.h" // Definition for our Foo class int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Foo *myFoo1 = [[Foo alloc] init]; Foo *myFoo2; [myFool setStrVal: @»This is the string»]; [myFool setlntVal: 12345]; [myFool setFloatVal: 98.6]; [NSKeyedArchiver archiveRootObject: myFool toFile: @"foo.arch"]; myFoo2 = [NSKeyedUnarchiver unarchiveObjectWithFile: @"foo.arch"]; NSLog (@"%@\n%i\n%g", [myFoo2 strVal], [myFoo2 intVal], [myFoo2 floatVal]); [myFool release]; [pool drain]; return 0; }
Вывод программы 19.8 This is the string (Это строка) 12345 98.6
Архивация трех пробных экземпляра из объекта выполняется с помощью следующих сообщений. [encoder encodeObject: strVal forKey: @"FoostrVar]; [encoder encodelnt: intVal forKey: @"FoointVal“]; [encoder encodeRoat: floatVal forKey: @"FoofloatVa!''];
Некоторые из базовых типов данных, такие как char, short, long и long long, не включены в таблицу 19.1; для них необходимо определить размер объекта дан-ных и использовать соответствующую процедуру. Например, тип short int обыч-но имеет размер 16 битов, int и long — 32 или 64 бита, и long long — 64 бита. (Размер любого типа данных определяется с помощью оператора sizeof, см. главу 13.) Например, данные типа short int нужно сохранить их сначала как тип int и затем архивировать с помощью encodeintforKey:. Для декодирования нужно использовать обратный процесс: применить decodelnt:forKey: и затем присвоить результат переменной типа short int. 19.4. Использование NSData для создания нестандартных архивов