《ObjectiveC20程序设计第19章归档ppt课件》由会员分享,可在线阅读,更多相关《ObjectiveC20程序设计第19章归档ppt课件(48页珍藏版)》请在金锄头文库上搜索。
1、武汉大学国际软件学院Objective-C 2.0程序设计第第19章章 归档归档 武汉大学国际软件学院Objective-C 2.0程序设计目录目录v19.1 使用使用XML属性列表进行归档属性列表进行归档v19.2 使用使用NSKeyedArchiver归档归档v19.3 编码方法和解码方法编码方法和解码方法v19.4 使用使用NSData创建自定义档案创建自定义档案v19.5 使用归档程序复制对象使用归档程序复制对象武汉大学国际软件学院Objective-C 2.0程序设计19.1 使用使用XML属性列表进行归档属性列表进行归档vMac OS X上的应用程序使用上的应用程序使用XML属性列
2、表属性列表或或plists)来存储诸如默认参数选择、应用程来存储诸如默认参数选择、应用程 序序设置和配置信息这样的数据,因而,了解如何创设置和配置信息这样的数据,因而,了解如何创建和读回这些数据很有用。然而,这些列表建和读回这些数据很有用。然而,这些列表 的归的归档用途是有限的,因为当为某个数据结构创建属档用途是有限的,因为当为某个数据结构创建属性列表时,没有保存特定的对象类,没有性列表时,没有保存特定的对象类,没有 存储对存储对同一对象的多个引用,也没有保持对象的可变性。同一对象的多个引用,也没有保持对象的可变性。武汉大学国际软件学院Objective-C 2.0程序设计19.1 使用使用X
3、ML属性列表进行归档属性列表进行归档v如果你的对象是如果你的对象是NSString、NSDictionary, NSArray、NSData或或NSNumber对象,你对象,你可以使可以使 用在这些类中实现的用在这些类中实现的writeToFile:atomically:方法将数据写到文方法将数据写到文件中。在写出某个字典或数组件中。在写出某个字典或数组 的情况下,该方法的情况下,该方法可以使用可以使用XML厲性列衷的格式写出数据。代码清厲性列衷的格式写出数据。代码清单单19-1显示了如何将在第显示了如何将在第15 章章“数字、字符串数字、字符串和集合和集合“中作为简易术语表而创建的字典作为属
4、中作为简易术语表而创建的字典作为属性列表写入文件中。性列表写入文件中。武汉大学国际软件学院Objective-C 2.0程序设计19.1 使用使用XML属性列表进行归档属性列表进行归档#import #import #import #import int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;NSDictionary *glossary =NSDictionary dictionaryWithObjectsAndKeys:”A class defined so oth
5、er 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 = NO)NSLog (”Save to file failed!”);pool drain;return 0;武汉大学国际软件学院Objective-C 2.0
6、程序设计19.1 使用使用XML属性列表进行归档属性列表进行归档writeToFile:atomically:消息被发送给字典对消息被发送给字典对象象glossary,使字典以属性列表使字典以属性列表 的形式写到文件的形式写到文件glossary中,中,atomically参数被设为参数被设为YES,表示希望首先将字典写入临时备份文表示希望首先将字典写入临时备份文 件中,并且件中,并且一且成功,将把最终数据转移到名为一且成功,将把最终数据转移到名为glossary的指定文件中。这是一种安全措施,的指定文件中。这是一种安全措施, 它保护文件它保护文件在一些情况下如系统在执行操作的过程中崩溃在一些
7、情况下如系统在执行操作的过程中崩溃时免受破坏。在这种情况下,原始的时免受破坏。在这种情况下,原始的glossary文件如果该文件已存在不会受到文件如果该文件已存在不会受到损害。损害。如果查看代码淸单如果查看代码淸单19-1中创建的中创建的glossary文件,文件,它的内容可能如下:它的内容可能如下:武汉大学国际软件学院Objective-C 2.0程序设计19.1 使用使用XML属性列表进行归档属性列表进行归档abstract classA class defined so other classes can inherit from it.adoptTo implement all the
8、 methods defined in a protocolarchivingStoring an object for later use. 武汉大学国际软件学院Objective-C 2.0程序设计19.1 使用使用XML属性列表进行归档属性列表进行归档v从所创建的从所创建的XML文件中可以看到,是以一种键文件中可以看到,是以一种键(.)值值(.) 对的形式对的形式将字典写入文件的,将字典写入文件的,v根据字典创建属性列表时,字典中的键必须全都是根据字典创建属性列表时,字典中的键必须全都是NSString对象。数组中的元素或宇典中对象。数组中的元素或宇典中 的值可以是的值可以是NSStri
9、ng, NSArray, NSDictionary, NSData, 或或NSNumber对象。对象。v要将文件中的要将文件中的XML属性列表读入你的程序,使用属性列表读入你的程序,使用dictionaryWithContentsOfFile:或或 arrayWithContentsOfFile:方法。要读回数据,使方法。要读回数据,使用用dataWithContentsOfFile:方法,要读回字符串方法,要读回字符串 对象,使用对象,使用stringWithContentsOfFile:方法。代码方法。代码淸单淸单19-2读回了代码清单读回了代码清单19-1中编写的术语表中编写的术语表,
10、然后然后输出其内容。输出其内容。武汉大学国际软件学院Objective-C 2.0程序设计19.1 使用使用XML属性列表进行归档属性列表进行归档#import #import #import #import #import int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;NSDictionary *glossary;glossary = NSDictionary dictionaryWithContentsOfFile: ”glossary”;for ( NSStri
11、ng *key in glossary )NSLog (”%: %”, key, glossary objectForKey: key);pool drain;return 0;输出:输出:archiving: Storing an object for later use.abstract class: A class defined so other classes can inherit from it.adopt: To implement all the methods defined in a protocol武汉大学国际软件学院Objective-C 2.0程序设计19.1 使用
12、使用XML属性列表进行归档属性列表进行归档v你的属性列表不必从你的属性列表不必从Objective-C程序中创建,程序中创建,属性列表可以来自任何的源。可以使用简单属性列表可以来自任何的源。可以使用简单 的文的文本编辑器,或使用本编辑器,或使用Mac OS X系统中位于系统中位于/Developer/Applications/Utilities目录下的目录下的Property List Editor程序来创建属性列表。程序来创建属性列表。武汉大学国际软件学院Objective-C 2.0程序设计19.2 使用使用NSKeyedArchiver归档归档v在带键的档案中,每个归档字段都有一个名称。
13、在带键的档案中,每个归档字段都有一个名称。归档某个对象时,会为它提供一个名称,即键。归档某个对象时,会为它提供一个名称,即键。从归档中检索该对象时,是根据这个键来检索它从归档中检索该对象时,是根据这个键来检索它的。这样,可以按照任意的顺序将对象写人归档的。这样,可以按照任意的顺序将对象写人归档井进行检素。另外,如果向类添加了新的实例变井进行检素。另外,如果向类添加了新的实例变量或删除了实例变量,程序也可以进行处理。量或删除了实例变量,程序也可以进行处理。v代码清单代码清单19-3展示了如何使用展示了如何使用NSKeyedArchiver类中的类中的archiveRootObject:toFil
14、e:方法将方法将 glossary存储到磁盘上,要使用该类,在你的存储到磁盘上,要使用该类,在你的程序中包含以下文件程序中包含以下文件v #import 武汉大学国际软件学院Objective-C 2.0程序设计19.2 使用使用NSKeyedArchiver归档归档#import #import #import #import #import int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;NSDictionary *glossary =NSDictionary di
15、ctionaryWithObjectsAndKeys:”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
16、 0;武汉大学国际软件学院Objective-C 2.0程序设计19.2 使用使用NSKeyedArchiver归档归档代码淸单代码淸单19-3并不在终端产生任何输出,但是语句并不在终端产生任何输出,但是语句NSKeyedArchiver archiveRootObject: glossary toFile: ”glossary.archive”;将字典将字典glossary写入文件写入文件glossary.archive中。可以为该文件指定任何路径名,在本中。可以为该文件指定任何路径名,在本例中,文件被写入当前目录下。例中,文件被写入当前目录下。以后通过以后通过NSKeyedUuarchiv
17、er的的unArChiveObjectWithFile:方法将创建的归档方法将创建的归档文件读人执行程序中,如代码清单文件读人执行程序中,如代码清单19-4所示。所示。#import #import #import #import #import #import int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;NSDictionary *glossary;glossary = NSKeyedUnarchiver unarchiveObjectWithFile:”glos
18、sary.archive”;for ( NSString *key in glossary )NSLog (”%: %”, key, glossary objectForKey: key);pool drain;return 0;武汉大学国际软件学院Objective-C 2.0程序设计19.2 使用使用NSKeyedArchiver归档归档v19.4输出:输出:v abstract class: A class defined so other classes can inherit from it.v adopt: To implement all the methods defined
19、in a protocolv archiving: Storing an object for later use.v语句语句;glossary = NSKeyedUnarchiver unarchiveObjectWithFile: ”glossary.archive”;v将指定的文件打开并读取文件的内容。该文件必须是前面归档操作的结果。可以为文将指定的文件打开并读取文件的内容。该文件必须是前面归档操作的结果。可以为文件指定完件指定完 整路径名或相对路径名,如本例所示。整路径名或相对路径名,如本例所示。v在恢复在恢复glossary之后,程序可以简单地通过枚举其内容来验证恢复是否成功。之后,
20、程序可以简单地通过枚举其内容来验证恢复是否成功。武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v要归档前面没有列出的对象,必须告知系统如何要归档前面没有列出的对象,必须告知系统如何归档或编码你的对象,以及如何解归归档或编码你的对象,以及如何解归 档或档或解码它们。这是按照解码它们。这是按照协议,在协议,在类定乂中添加类定乂中添加encodeWithCoder:方法和方法和 initWithCoder:方法实现的。对于我们地址簿方法实现的。对于我们地址簿的例子,必须向的例子,必须向AddressBook类和类和AddressCard类添类
21、添 加这些方法。加这些方法。武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v每次归档程序想要根据指定类编码对象时,都将每次归档程序想要根据指定类编码对象时,都将调用调用encodeWithCoder:方法,该方法告知方法,该方法告知 归档程序如何进行归档。类似地,毎次从指定的归档程序如何进行归档。类似地,毎次从指定的类解码对象时,就会调用类解码对象时,就会调用initWithCoder方法。方法。武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v一般而言,编码方法应该指定如何归档想
22、要保存一般而言,编码方法应该指定如何归档想要保存的对象中的每个实例变量。幸运的是,这的对象中的每个实例变量。幸运的是,这 些都有些都有帮助可査。对于前面描述的基本帮助可査。对于前面描述的基本Objective-C类,可以使用类,可以使用encodeObject:forKey:方法。方法。相相 反,对于基本的反,对于基本的C数据类型如整型和浮点型)数据类型如整型和浮点型),可以使用表,可以使用表19-1中列出的某种方法。解码方中列出的某种方法。解码方法法initWlthCoder:的工作方式正好相反:它使的工作方式正好相反:它使用用decodeObjecUorKey:来解码基本的来解码基本的Ob
23、jective-C类类 使用下表列出的相应解玛方法使用下表列出的相应解玛方法来解码基本的数据类型。来解码基本的数据类型。武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v代码清单代码清单19-5为为AddressCard类和类和AddressBook类类都添加了两个编码和解码方法都添加了两个编码和解码方法v#import v#import v#import vinterface AddressCard: NSObject vvNSStr
24、ing *name;vNSString *;vvproperty (copy, nonatomic) NSString *name, *;v-(void) setName: (NSString *) theName andEmail: (NSString *) theEmail;v-(NSComparisonResult) compareNames: (id) element;v-(void) print;v/ Additional methods for NSCopying protocolv-(AddressCard *) copyWithZone: (NSZone *) zone;v-(
25、void) retainName: (NSString *) theName andEmail: (NSString *) theEmail;vend武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v下面是要添加到下面是要添加到AddressCard类实现文件的两个新方类实现文件的两个新方法:法:v-(void) encodeWithCoder: (NSCoder *) encodervvencoder encodeObject: name forKey: ”AddressCardName”;vencoder encodeObject:
26、forKey: ”AddressCardEmail”;vv-(id) initWithCoder: (NSCoder *) decodervvname = decoder decodeObjectforKey: ”AddressCardName” retain;v = decoder decodeObjectforKey: ”AddressCardEmail” retain;vreturn self;v武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v该程序向编码方法该程序向编码方法encodeWithCoder:传人一传人一个个NSCo
27、der对象作为参数。由干对象作为参数。由干AddressCard类类 直接继承自直接继承自Nsobject,所以,所以无需担心编码继承的实例变量。如果的确担心,无需担心编码继承的实例变量。如果的确担心,并且知道类的子类符合并且知道类的子类符合NSCoding协议的要求,协议的要求,那么应该用下面的语句开始编码方法,确保继承那么应该用下面的语句开始编码方法,确保继承的实例变量也被编码:的实例变量也被编码:v super encodeWithCoder: encoder;武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v对于地址簿来说,有两个
28、名为对于地址簿来说,有两个名为name和和email的实例变的实例变量。因为它们都是量。因为它们都是NSString对象,所以使用对象,所以使用encodeObjectiforKey:方法依次对它们进行编码,方法依次对它们进行编码,然后将这两个实例变量添加到归档文件中。然后将这两个实例变量添加到归档文件中。vencodeObjectforKey:方法编码对象并将其存储在指方法编码对象并将其存储在指定的键下,以后可使用该键检索对象。定的键下,以后可使用该键检索对象。 键名是任意的,键名是任意的,所以只要在检索编码数据时使用的名称与归档编码所以只要在检索编码数据时使用的名称与归档编码时使用的名称相
29、同,时使用的名称相同, 就可以指定任何键名。唯一可能就可以指定任何键名。唯一可能出现冲突的情况是,为正在编码的对象子类使用了相同的出现冲突的情况是,为正在编码的对象子类使用了相同的键。键。 为了防止这种情况出现,制订归档的键时,可将类为了防止这种情况出现,制订归档的键时,可将类名放在实例变量名的前面,代码淸单名放在实例变量名的前面,代码淸单19-5就就 是这样做的。是这样做的。武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v注意,注意,encodeObjectForKey:方法可以用于任何在其类中实现对方法可以用于任何在其类中实现对应应
30、encodeWithCoder:方法的方法的 对象对象.v解码的过程刚好相反。传递给解码的过程刚好相反。传递给initWithCoder的参数也是的参数也是NSCoder对象,不必担心这个参数,对象,不必担心这个参数, 只要记住它是获得该消息只要记住它是获得该消息对于每个想要从归档文件中提取的对象的对象。对于每个想要从归档文件中提取的对象的对象。v同样,由于同样,由于AddressCard类直接继承自类直接继承自NSObject,所以不必担,所以不必担心解码继承的实例变心解码继承的实例变i。假如。假如 的确担心,那么应在解码方法的开始插的确担心,那么应在解码方法的开始插人下列行假设类的超类符合
31、人下列行假设类的超类符合NSCoding协议的要求):协议的要求):v self = super initwithCoder:decoder;v通过调用通过调用decodeObjectforKey:方法并传递在编码变量时使用的方法并传递在编码变量时使用的相同键,就可解码每个实例相同键,就可解码每个实例 变量。变量。v类似于类似于AddressCard类,你为类,你为AddressBook类添加了两个编码类添加了两个编码和解码方法。在接口文件中只需更改指令,以声明现在和解码方法。在接口文件中只需更改指令,以声明现在AddressBook类已经符合类已经符合NSCoding协议。更改如下所示:协议
32、。更改如下所示:v interface AddressBook: NSObject 武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v下面是实现文件中所含的方法定义:下面是实现文件中所含的方法定义:v-(void) encodeWithCoder: (NSCoder *) encodervvencoder encodeObject: bookName forKey: “AddressBookBookName”;vencoder encodeObject: book forKey: ”AddressBookBook”;vv-(id) ini
33、tWithCoder: (NSCoder *) decodervvbookName = decoder decodeObjectForKey: ”AddressBookBookName” retain;vbook = decoder decodeObjectForKey: ”AddressBookBook” retain;vreturn self;vv以下代码清单以下代码清单19-6是它的测试程序。是它的测试程序。武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法#import “AddressBook.h”#import int main
34、 (int argc, char *argv)NSString *aName = ”Julia Kochan”;NSString *aEmail = ”jewls337axlc”;NSString *bName = ”Tony Iannino”;NSString *bEmail = ”tony.ianninotechfitness”;NSString *cName = ”Stephen Kochan”;NSString *cEmail = ”stevesteve_kochan”;NSString *dName = ”Jamie Baker”;NSString *dEmail = ”jbaker
35、hitmail”;NSAutoreleasePool * pool = NSAutoreleasePool alloc init;AddressCard *card1 = AddressCard alloc init;AddressCard *card2 = AddressCard alloc init;AddressCard *card3 = AddressCard alloc init;AddressCard *card4 = AddressCard alloc init;AddressBook *myBook = AddressBook alloc;/ First set up four
36、 address cardscard1 setName: aName andEmail: aEmail;card2 setName: bName andEmail: bEmail;card3 setName: cName andEmail: cEmail;card4 setName: dName andEmail: dEmail;myBook = myBook initWithName: ”Steves Address Book”;武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法/ Add some cards to the addres
37、s bookmyBook addCard: card1;myBook addCard: card2;myBook addCard: card3;myBook addCard: card4;myBook sort;if (NSKeyedArchiver archiveRootObject: myBook toFile: ”addrbook.arch” = NO)NSLog (”archiving failed”);card1 release;card2 release;card3 release;card4 release;myBook release;pool drain;return 0;
38、这个程序创建了一个地址簿,然后将它归档到文件这个程序创建了一个地址簿,然后将它归档到文件addrbook.arch中。在创建归档文件的过程中中。在创建归档文件的过程中,注意,注意AddressBook类和类和AddressCard类中的编码方法都被调用了。如果想要验证,可以向类中的编码方法都被调用了。如果想要验证,可以向这些方法添加一些这些方法添加一些NSLog调用。调用。武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v代码淸单代码淸单19-7展示了如何将归档读人内存以根据文件创建地址簿。展示了如何将归档读人内存以根据文件创建地址簿。v
39、#import “AddressBook.h”v#import vint main (int argc, char *argv)vvAddressBook *myBook;vNSAutoreleasePool * pool = NSAutoreleasePool alloc init;vmyBook = NSKeyedUnarchiver unarchiveObjectWithFile: ”addrbook.arch”;vmyBook list;vpool drain;vreturn 0;vv输出:输出:v= Contents of: Steves Address Book =vJamie B
40、aker jbakerhitmailvJulia Kochan jewls337axlcvStephen Kochan stevesteve_kochanvTony Iannino tony.ianninotechfitnessv=武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v在解码地址簿的过程中,自动调用向两个类添加的解码方法。注意将在解码地址簿的过程中,自动调用向两个类添加的解码方法。注意将地址薄读回程序是多么容易。地址薄读回程序是多么容易。v前面说过,前面说过,encodeObject:forKey:方法作用子内置类以及根据方法
41、作用子内置类以及根据NSCoding协议为其编写编码协议为其编写编码 和解码方法的类。如果你的实例包含和解码方法的类。如果你的实例包含基本数据类型,如整型或浮点型,那么需要知道如何对它基本数据类型,如整型或浮点型,那么需要知道如何对它 们进行编们进行编码和解码参见表码和解码参见表19-1)。v下面是一个类的简单定义,这个类名为下面是一个类的简单定义,这个类名为Foo,它包含三个实例变量:,它包含三个实例变量:一个是一个是NSString类型类型, 一个一个int型,一个型,一个float型。这个类包含一个型。这个类包含一个赋值方法、三个取值方法以及两个用于归档的编码赋值方法、三个取值方法以及两
42、个用于归档的编码/解码方法:解码方法:v interface Foo: NSObject vvNSString *strVal;vint intVal;vfloat floatVal;vvproperty (copy, nonatomic) NSString *strVal;vproperty int intVal;vproperty float floatVal;vend武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v实现文件如下:实现文件如下:vimplementation Foovsynthesize strVal, intVal
43、, floatVal;v-(void) encodeWithCoder: (NSCoder *) encodervvencoder encodeObject: strVal forKey: ”FoostrVal”;vencoder encodeInt: intVal forKey: ”FoointVal”;vencoder encodeFloat: floatVal forKey: ”FoofloatVal”;vv-(id) initWithCoder: (NSCoder *) decodervvstrVal = decoder decodeObjectForKey: ”FoostrVal”
44、retain;vintVal = decoder decodeIntForKey: ”FoointVal”;vfloatVal = decoder decodeFloatForKey: ”FoofloatVal”;vreturn self;vvend武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v编码例程首先使用前面用过的编码例程首先使用前面用过的encodeObject:forKey:对象来编码字符串值对象来编码字符串值strVal如上面内容所示。如上面内容所示。v在代码淸单在代码淸单19-8中,我们创建了一个中,我们创建了一个Foo
45、对象,对象,把它归档到一个文件,解归档,然后显示。把它归档到一个文件,解归档,然后显示。武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法#import #import #import #import #import “Foo.h” / Definition for our Foo classint main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;Foo *myFoo1 = Foo alloc init;Foo *myFoo
46、2;myFoo1 setStrVal: ”This is the string”;myFoo1 setIntVal: 12345;myFoo1 setFloatVal: 98.6;NSKeyedArchiver archiveRootObject: myFoo1 toFile: ”foo.arch”;myFoo2 = NSKeyedUnarchiver unarchiveObjectWithFile: ”foo.arch”;NSLog (”%n%in%g”, myFoo2 strVal, myFoo2 intVal, myFoo2 floatVal);myFoo1 release;pool d
47、rain;return 0;输出:输出:This is the string1234598.6武汉大学国际软件学院Objective-C 2.0程序设计19.3 编码方法和解码方法编码方法和解码方法v以下消息归档了对象的以下消息归档了对象的3个实例变量:个实例变量:vencoder encodeObject: strVal forKey: ”FoostrVal”;vencoder encodeInt: intVal forKey: ”FoointVal”;vencoder encodeFloat: floatVal forKey: ”FoofloatVal”;v 一些基本数据类型一些基本数据类
48、型如如char、short、long和和long long在表在表19-1中没有列出。你必须确定数据对象的大中没有列出。你必须确定数据对象的大小并使用相应的例程小并使用相应的例程d例如,例如,short int通常是通常是16位的,位的,而而int和和long可以是可以是32位或位或64位,位,long long是是64位位的可以使用第的可以使用第13章介绍的章介绍的sizeof运算符确定任何数据运算符确定任何数据类型的大小)。所以类型的大小)。所以 要归档要归档shortint的数据,首先将其的数据,首先将其存储在存储在int中,然后使用中,然后使用encodelntforKey:归档它。归
49、档它。反向执行该反向执行该 过程可恢复它:使用过程可恢复它:使用decodelntForKey:,然后将其赋值给然后将其赋值给short int变量。变量。武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用使用NSData创建自定义档案创建自定义档案v有时可能不想和前面示例程序一样,使用有时可能不想和前面示例程序一样,使用archiveRootObjectToFile:方法将对象直接方法将对象直接写入文件。比如,可能想收集一些或佥部对象,写入文件。比如,可能想收集一些或佥部对象,并将其存储到单个档案文件中。在并将其存储到单个档案文件中。在Objective-C中,通过使中
50、,通过使 用名为用名为NSData的通用数据流对象的通用数据流对象类,可以实现上述功能,在第类,可以实现上述功能,在第16章,我们简单地章,我们简单地提到过这个类。提到过这个类。 武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用使用NSData创建自定义档案创建自定义档案v正如第正如第16章所提到的,章所提到的,NSData对象可以用来对象可以用来保留一块内存空间以备后来存储敉据。这些数保留一块内存空间以备后来存储敉据。这些数 据据空间的典型应用是怍为一些数据的临时存储空间,空间的典型应用是怍为一些数据的临时存储空间,如随后将被写人文件,或可能用于容纳从如随后将被写人文
51、件,或可能用于容纳从 磁盘读磁盘读取的文件內容。创建可变数据空间的最简单方式取的文件內容。创建可变数据空间的最简单方式是使用是使用data方法方法武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用使用NSData创建自定义档案创建自定义档案 dataArea = NSMutabletata date;该语句创建一个空缓冲区,其大小随程序执行需要该语句创建一个空缓冲区,其大小随程序执行需要而扩展。而扩展。作为一个简单的例子,假设你想将地址簿和一个作为一个简单的例子,假设你想将地址簿和一个Foo对象归档到同一个文件。假设对于这个对象归档到同一个文件。假设对于这个 例子,例子,
52、你已经向你已经向AddressBook和和AddressCard类添类添加了一个带键的归档方法加了一个带键的归档方法参见如下代码参见如下代码武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用使用NSData创建自定义档案创建自定义档案#import #import #import #import #import #import #import “AddressBook.h”#import “Foo.h”int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init
53、;Foo *myFoo1 = Foo alloc init;Foo *myFoo2;NSMutableData *dataArea;NSKeyedArchiver *archiver;AddressBook *myBook;/ Insert code from Program 19.7 to create an Address Book/ in myBook containing four address cards武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用使用NSData创建自定义档案创建自定义档案#import #import #import #import
54、#import #import #import “AddressBook.h”#import “Foo.h”int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;Foo *myFoo1 = Foo alloc init;Foo *myFoo2;NSMutableData *dataArea;NSKeyedArchiver *archiver;AddressBook *myBook;/ Insert code from Program 19.7 to create an Add
55、ress Book/ in myBook containing four address cards武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用使用NSData创建自定义档案创建自定义档案myFoo1 setStrVal: ”This is the string”;myFoo1 setIntVal: 12345;myFoo1 setFloatVal: 98.6;/ Set up a data area and connect it to an NSKeyedArchiver objectdataArea = NSMutableData data;archiver =
56、 NSKeyedArchiver allocinitForWritingWithMutableData: dataArea;/ Now we can begin to archive objectsarchiver encodeObject: myBook forKey: ”myaddrbook”;archiver encodeObject: myFoo1 forKey: ”myfoo1”;archiver finishEncoding;/ Write the archived data are to a fileif ( dataArea writeToFile: ”myArchive” a
57、tomically: YES = NO)NSLog (”Archiving failed!”);archiver release;myFoo1 release;pool drain;return 0;武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用归档程序复制对象使用归档程序复制对象v分配一个分配一个NSKeyedArchiver对象之后,发送对象之后,发送initForWritingWithMutableData:消息,以指定要消息,以指定要 写入归档写入归档数据的存储空间。这就是前面创建的数据的存储空间。这就是前面创建的NSMutabledata空间空间dataAr
58、ea。此时,就可以向存储在。此时,就可以向存储在archives中的中的NSKeyedArchiver对象发送编码消息,以归档该程序中的对象对象发送编码消息,以归档该程序中的对象.实际上,所有实际上,所有 编码消息在收到编码消息在收到finishEncoding消息之前都被归档消息之前都被归档并存储在指定的数据空间内并存储在指定的数据空间内.v这里,有两个对象需要编码这里,有两个对象需要编码-个是地址簿,另一个是个是地址簿,另一个是Foo对象,对干对象,对干这些对象可以使这些对象可以使v用用encodeObject:forKey:,因为在前面你已经为,因为在前面你已经为AddressBook、
59、AddressCard和和Foo类实现了编码方法和解码类实现了编码方法和解码方法理解这个概念很重要)方法理解这个概念很重要)v在归档这两个对象时,向在归档这两个对象时,向archiver对象发送一条对象发送一条finishEncoding消息。之后,就不能编码其他对象,你需要发送此消息以完成归档过消息。之后,就不能编码其他对象,你需要发送此消息以完成归档过程。程。武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用归档程序复制对象使用归档程序复制对象v此时,你预留的那块名为此时,你预留的那块名为dataArea的空间包含归档对象,这些对的空间包含归档对象,这些对象可以一种可
60、写入文件的格式存在。消息表达式象可以一种可写入文件的格式存在。消息表达式v data writeToFile: ”myArchive” atomically: YESv 向你的数据流发送向你的数据流发送writeToFile:atomically:消息,请求它把消息,请求它把它的数据写人指定文件,它的数据写人指定文件, 这个文件名为这个文件名为myArchive。v从从if语句可以看到语句可以看到writeToFile:atomically:方法返回一个方法返回一个BOOL值:如果写值:如果写 操作成功就返回操作成功就返回YES,如果失败可能是指定了无效的,如果失败可能是指定了无效的路径名或文
61、件系统已满就返回路径名或文件系统已满就返回NO。v从档案文件中恢复数据很简单从档案文件中恢复数据很简单所做的工作只需和归档文件相反,所做的工作只需和归档文件相反,首先,需要像以前那首先,需要像以前那 样分配一个数据空间。然后,把挡案文件中的样分配一个数据空间。然后,把挡案文件中的数据读入该数据空间,然后,需要创建一个数据读入该数据空间,然后,需要创建一个 NSKeyedUnarchiver对象,并告知它从指定空间解码数据。必对象,并告知它从指定空间解码数据。必须调用解码方法来提取和解码归须调用解码方法来提取和解码归 档的对象,做完之后,向档的对象,做完之后,向NSKeyedUnarchiver
62、对象发送一条对象发送一条finishDecoding消息消息 代码代码清单清单19-10实现了所有任务。实现了所有任务。武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用归档程序复制对象使用归档程序复制对象Program 19.10#import #import #import #import #import #import #import “AddressBook.h”#import “Foo.h”int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;
63、NSData *dataArea;NSKeyedUnarchiver *unarchiver;Foo *myFoo1;AddressBook *myBook;/ Read in the archive and connect an/ NSKeyedUnarchiver object to itdataArea = NSData dataWithContentsOfFile: ”myArchive”;武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用归档程序复制对象使用归档程序复制对象if (! dataArea) NSLog (“Cant read back archiv
64、e file!”);Return (1);unarchiver = NSKeyedUnarchiver allocinitForReadingWithData: dataArea;/ Decode the objects we previously stored in the archivemyBook = unarchiver decodeObjectForKey: ”myaddrbook”;myFoo1 = unarchiver decodeObjectForKey: ”myfoo1”;unarchiver finishDecoding;unarchiver release;/ Verif
65、y that the restore was successfulmyBook list;NSLog (“%n%in%g”, myFoo1 strVal,myFoo1 intVal, myFoo1 floatVal);pool release;return 0;武汉大学国际软件学院Objective-C 2.0程序设计19.4 使用归档程序复制对象使用归档程序复制对象输出:输出:= Contents of: Steves Address Book =Jamie Baker jbakerhitmailJulia Kochan jewls337axlcStephen Kochan steveste
66、ve_kochanTony Iannino tony.ianninotechfitness=This is the string1234598.6输出结果验证了你的地址簿和输出结果验证了你的地址簿和Foo对象已成功地从档案文件中恢复了。对象已成功地从档案文件中恢复了。武汉大学国际软件学院Objective-C 2.0程序设计19.5 使用归档程序复制对象使用归档程序复制对象v在代码清单在代码清单18-2中,尝试创建包含可变字符串中,尝试创建包含可变字符串元素的数组副本,并且了解了如何进行浅复制。元素的数组副本,并且了解了如何进行浅复制。也就是,没有复制实际的字符串本身,只是复制也就是,没有复制
67、实际的字符串本身,只是复制对它们的引用。对它们的引用。v可以使用可以使用Foundation的归档能力来创建对象的的归档能力来创建对象的深复制。例如,代码清单深复制。例如,代码清单19-11通过通过data Array 归档到一个缓冲区,然后把它解归档,将归档到一个缓冲区,然后把它解归档,将结果指派给结果指派给dataArray2,从而将从而将dataArray复复制给制给 dataArray2对于这个过程,不需要使用对于这个过程,不需要使用文件。归裆和解归档过程都可以在内存中发生,文件。归裆和解归档过程都可以在内存中发生,武汉大学国际软件学院Objective-C 2.0程序设计19.5 使
68、用归档程序复制对象使用归档程序复制对象Program 19.11#import #import #import #import #import int main (int argc, char *argv)NSAutoreleasePool *pool = NSAutoreleasePool alloc init;NSData *data;NSMutableArray *dataArray = NSMutableArray arrayWithObjects:NSMutableString stringWithString: ”one”,NSMutableString stringWithStr
69、ing: ”two”,NSMutableString stringWithString: ”three”,nil;武汉大学国际软件学院Objective-C 2.0程序设计19.5 使用归档程序复制对象使用归档程序复制对象NSMutableArray *dataArray2;NSMutableString *mStr;/ Make a deep copy using the archiverdata = NSKeyedArchiver archivedDataWithRootObject: dataArray;dataArray2 = NSKeyedUnarchiver unarchiveOb
70、jectWithData: data;mStr = dataArray2 objectAtIndex: 0;mStr appendString: ”ONE”;NSLog (”dataArray: “);for ( NSString *elem in dataArray )NSLog (“%”, elem);NSLog (”ndataArray2: “);for ( NSString *elem in dataArray2 )NSLog (“%”, elem);pool drsin;return 0;武汉大学国际软件学院Objective-C 2.0程序设计19.5 使用归档程序复制对象使用归档
71、程序复制对象输出输出:dataArray:onetwothreedataArray2:oneONEtwothree武汉大学国际软件学院Objective-C 2.0程序设计19.5 使用归档程序复制对象使用归档程序复制对象 这个输出结果验证了更改这个输出结果验证了更改dataArray2的第一个的第一个元素对元素对dataArray的第一个元素并没有影响,的第一个元素并没有影响, 这是因为在归档和解归档过程中产生的是字符串这是因为在归档和解归档过程中产生的是字符串的新副本。代码凊单的新副本。代码凊单19-11中的复制操作是通过中的复制操作是通过以下两行实现的:以下两行实现的: data = N
72、SKeyedArchiver archivedDataWithRootObject: dataArray; dataArray2 = NSKeyedUnarchiver unarchiveObjectWithData: data; 甚至可以避免中间陚值,只用一条语句来执行甚至可以避免中间陚值,只用一条语句来执行复制,如下所示:复制,如下所示:dataArray2 = NSKeyedUnarchiver unarchiveObjectWithData:NSKeyedArchiver archivedDataWithRootObject: dataArray; 下次需要生成一个对象或不支持下次需要生成一个对象或不支持NSCopying协议的对象的深复制时,应该记协议的对象的深复制时,应该记住这项技术。住这项技术。