




已阅读5页,还剩43页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第19章 归档,目录,19.1 使用XML属性列表进行归档 19.2 使用NSKeyedArchiver归档 19.3 编码方法和解码方法 19.4 使用NSData创建自定义档案 19.5 使用归档程序复制对象,19.1 使用XML属性列表进行归档,Mac OS X上的应用程序使用XML属性列表(或plists)来存储诸如默认参数选择、应用程 序设置和配置信息这样的数据,因此,了解如何创建和读回这些数据很有用。然而,这些列表 的归档用途是有限的,因为当为某个数据结构创建属性列表时,没有保存特定的对象类,没有 存储对同一对象的多个引用,也没有保持对象的可变性。,19.1 使用XML属性列表进行归档,如果你的对象是NSString、NSDictionary, NSArray、NSData或NSNumber对象,你可以使 用在这些类中实现的writeToFile:atomically:方法将数据写到文件中。在写出某个字典或数组 的情况下,该方法可以使用XML厲性列衷的格式写出数据。代码清单19-1显示了如何将在第15 章“数字、字符串和集合“中作为简易术语表而创建的字典作为属性列表写入文件中。,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 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 = NO) NSLog (”Save to file failed!”); pool drain; return 0; ,19.1 使用XML属性列表进行归档,writeToFile:atomically:消息被发送给字典对象glossary,使字典以属性列表 的形式写到文件glossary中,atomically参数被设为YES,表示希望首先将字典写入临时备份文 件中,并且一且成功,将把最终数据转移到名为glossary的指定文件中。这是一种安全措施, 它保护文件在一些情况下(如系统在执行操作的过程中崩溃时)免受破坏。在这种情况下,原始的glossary文件(如果该文件已存在)不会受到损害。 如果查看代码淸单19-1中创建的glossary文件,它的内容可能如下:,19.1 使用XML属性列表进行归档, abstract class A class defined so other classes can inherit from it. adopt To implement all the methods defined in a protocol archiving Storing an object for later use. ,19.1 使用XML属性列表进行归档,从所创建的XML文件中可以看到,是以一种键(.)值(.) 对的形式将字典写入文件的, 根据字典创建属性列表时,字典中的键必须全都是NSString对象。数组中的元素或宇典中 的值可以是NSString, NSArray, NSDictionary, NSData, 或NSNumber对象。 要将文件中的XML属性列表读入你的程序,使用dictionaryWithContentsOfFile:或 arrayWithContentsOfFile:方法。要读回数据,使用dataWithContentsOfFile:方法,要读回字符串 对象,使用stringWithContentsOfFile:方法。代码淸单19-2读回了代码清单19-1中编写的术语表, 然后输出其内容。,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 ( NSString *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,19.1 使用XML属性列表进行归档,你的属性列表不必从Objective-C程序中创建,属性列表可以来自任何的源。可以使用简单 的文本编辑器,或使用Mac OS X系统中位于/Developer/Applications/Utilities目录下的Property List Editor程序来创建属性列表。,19.2 使用NSKeyedArchiver归档,在带键的档案中,每个归档字段都有一个名称。归档某个对象时,会为它提供一个名称,即键。从归档中检索该对象时,是根据这个键来检索它的。这样,可以按照任意的顺序将对象写人归档井进行检素。另外,如果向类添加了新的实例变量或删除了实例变量,程序也可以进行处理。 代码清单19-3展示了如何使用NSKeyedArchiver类中的archiveRootObject:toFile:方法将 glossary存储到磁盘上,要使用该类,在你的程序中包含以下文件 #import ,19.2 使用NSKeyedArchiver归档,#import #import #import #import #import int main (int argc, 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 ; NSKeyedArchiver archiveRootObject: glossary toFile: ”glossary.archive”; pool release; return 0; ,19.2 使用NSKeyedArchiver归档,代码淸单19-3并不在终端产生任何输出,但是语句 NSKeyedArchiver archiveRootObject: glossary toFile: ”glossary.archive”; 将字典glossary写入文件glossary.archive中。可以为该文件指定任何路径名,在本例中,文件被写入当前目录下。 以后通过NSKeyedUuarchiver的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: ”glossary.archive”; for ( NSString *key in glossary ) NSLog (”%: %”, key, glossary objectForKey: key); pool drain; return 0; ,19.2 使用NSKeyedArchiver归档,19.4输出: abstract class: A class defined so other classes can inherit from it. adopt: To implement all the methods defined in a protocol archiving: Storing an object for later use. 语句;glossary = NSKeyedUnarchiver unarchiveObjectWithFile: ”glossary.archive”; 将指定的文件打开并读取文件的内容。该文件必须是前面归档操作的结果。可以为文件指定完 整路径名或相对路径名,如本例所示。 在恢复glossary之后,程序可以简单地通过枚举其内容来验证恢复是否成功。,19.3 编码方法和解码方法,要归档前面没有列出的对象,必须告知系统如何归档(或编码)你的对象,以及如何解归 档(或解码)它们。这是按照协议,在类定乂中添加encodeWithCoder:方法和 initWithCoder:方法实现的。对于我们地址簿的例子,必须向AddressBook类和AddressCard类添 加这些方法。,19.3 编码方法和解码方法,每次归档程序想要根据指定类编码对象时,都将调用encodeWithCoder:方法,该方法告知 归档程序如何进行归档。类似地,毎次从指定的类解码对象时,就会调用initWithCoder方法。,19.3 编码方法和解码方法,一般而言,编码方法应该指定如何归档想要保存的对象中的每个实例变量。幸运的是,这 些都有帮助可査。对于前面描述的基本Objective-C类,可以使用encodeObject:forKey:方法。相 反,对于基本的C数据类型(如整型和浮点型),可以使用表19-1中列出的某种方法。解码方法initWlthCoder:的工作方式正好相反:它使用decodeObjecUorKey:来解码基本的Objective-C类 使用下表列出的相应解玛方法来解码基本的数据类型。,19.3 编码方法和解码方法,19.3 编码方法和解码方法,代码清单19-5为AddressCard类和AddressBook类都添加了两个编码和解码方法 #import #import #import interface AddressCard: NSObject NSString *name; NSString *email; property (copy, nonatomic) NSString *name, *email; -(void) setName: (NSString *) theName andEmail: (NSString *) theEmail; -(NSComparisonResult) compareNames: (id) element; -(void) print; / Additional methods for NSCopying protocol -(AddressCard *) copyWithZone: (NSZone *) zone; -(void) retainName: (NSString *) theName andEmail: (NSString *) theEmail; end,19.3 编码方法和解码方法,下面是要添加到AddressCard类实现文件的两个新方法: -(void) encodeWithCoder: (NSCoder *) encoder encoder encodeObject: name forKey: ”AddressCardName”; encoder encodeObject: email forKey: ”AddressCardEmail”; -(id) initWithCoder: (NSCoder *) decoder name = decoder decodeObjectforKey: ”AddressCardName” retain; email = decoder decodeObjectforKey: ”AddressCardEmail” retain; return self; ,19.3 编码方法和解码方法,该程序向编码方法encodeWithCoder:传人一个NSCoder对象作为参数。由干AddressCard类 直接继承自Nsobject,所以无需担心编码继承的实例变量。如果的确担心,并且知道类的子类符合NSCoding协议的要求,那么应该用下面的语句开始编码方法,确保继承的实例变量也被编码: super encodeWithCoder: encoder;,19.3 编码方法和解码方法,对于地址簿来说,有两个名为name和email的实例变量。因为它们都是NSString对象,所以使用encodeObjectiforKey:方法依次对它们进行编码,然后将这两个实例变量添加到归档文件中。 encodeObjectforKey:方法编码对象并将其存储在指定的键下,以后可使用该键检索对象。 键名是任意的,所以只要在检索(编码)数据时使用的名称与归档(编码)时使用的名称相同, 就可以指定任何键名。唯一可能出现冲突的情况是,为正在编码的对象子类使用了相同的键。 为了防止这种情况出现,制订归档的键时,可将类名放在实例变量名的前面,代码淸单19-5就 是这样做的。,19.3 编码方法和解码方法,注意,encodeObjectForKey:方法可以用于任何在其类中实现对应encodeWithCoder:方法的 对象. 解码的过程刚好相反。传递给initWithCoder的参数也是NSCoder对象,不必担心这个参数, 只要记住它是获得该消息(对于每个想要从归档文件中提取的对象)的对象。 同样,由于AddressCard类直接继承自NSObject,所以不必担心解码继承的实例变i。如果 的确担心,那么应在解码方法的开始插人下列行(假设类的超类符合NSCoding协议的要求): self = super initwithCoder:decoder; 通过调用decodeObjectforKey:方法并传递在编码变量时使用的相同键,就可解码每个实例 变量。 类似于AddressCard类,你为AddressBook类添加了两个编码和解码方法。在接口文件中只需更改指令,以声明现在AddressBook类已经符合NSCoding协议。更改如下所示: interface AddressBook: NSObject ,19.3 编码方法和解码方法,下面是实现文件中所含的方法定义: -(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是它的测试程序。,19.3 编码方法和解码方法,#import “AddressBook.h” #import int main (int argc, char *argv) NSString *aName = ”Julia Kochan”; NSString *aEmail = ””; NSString *bName = ”Tony Iannino”; NSString *bEmail = ””; NSString *cName = ”Stephen Kochan”; NSString *cEmail = ”stevesteve_”; NSString *dName = ”Jamie Baker”; NSString *dEmail = ””; 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 address cards card1 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”;,19.3 编码方法和解码方法,/ Add some cards to the address book myBook 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; 这个程序创建了一个地址簿,然后将它归档到文件addrbook.arch中。在创建归档文件的过程中,注意AddressBook类和AddressCard类中的编码方法都被调用了。如果想要验证,可以向这些方法添加一些NSLog调用。,19.3 编码方法和解码方法,代码淸单19-7展示了如何将归档读人内存以根据文件创建地址簿。 #import “AddressBook.h” #import int main (int argc, char *argv) AddressBook *myBook; NSAutoreleasePool * pool = NSAutoreleasePool alloc init; myBook = NSKeyedUnarchiver unarchiveObjectWithFile: ”addrbook.arch”; myBook list; pool drain; return 0; 输出: = Contents of: Steves Address Book = Jamie Baker Julia Kochan Stephen Kochan stevesteve_ Tony Iannino =,19.3 编码方法和解码方法,在解码地址簿的过程中,自动调用向两个类添加的解码方法。注意将地址薄读回程序是多么容易。 前面说过,encodeObject:forKey:方法作用子内置类以及根据NSCoding协议为其编写编码 和解码方法的类。如果你的实例包含基本数据类型,如整型或浮点型,那么需要知道如何对它 们进行编码和解码(参见表19-1)。 下面是一个类的简单定义,这个类名为Foo,它包含三个实例变量:一个是NSString类型, 一个int型,一个float型。这个类包含一个赋值方法、三个取值方法以及两个用于归档的编码/解码方法: interface Foo: NSObject NSString *strVal; int intVal; float floatVal; property (copy, nonatomic) NSString *strVal; property int intVal; property float floatVal; end,19.3 编码方法和解码方法,实现文件如下: implementation Foo synthesize strVal, intVal, floatVal; -(void) encodeWithCoder: (NSCoder *) encoder encoder encodeObject: strVal forKey: ”FoostrVal”; encoder encodeInt: intVal forKey: ”FoointVal”; encoder encodeFloat: floatVal forKey: ”FoofloatVal”; -(id) initWithCoder: (NSCoder *) decoder strVal = decoder decodeObjectForKey: ”FoostrVal” retain; intVal = decoder decodeIntForKey: ”FoointVal”; floatVal = decoder decodeFloatForKey: ”FoofloatVal”; return self; end,19.3 编码方法和解码方法,编码例程首先使用前面用过的encodeObject:forKey:对象来编码字符串值strVal如上面内容所示。 在代码淸单19-8中,我们创建了一个Foo对象,把它归档到一个文件,解归档,然后显示。,19.3 编码方法和解码方法,#import #import #import #import #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; 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 drain; return 0; 输出: This is the string 12345 98.6,19.3 编码方法和解码方法,以下消息归档了对象的3个实例变量: encoder encodeObject: strVal forKey: ”FoostrVal”; encoder encodeInt: intVal forKey: ”FoointVal”; encoder encodeFloat: floatVal forKey: ”FoofloatVal”; 一些基本数据类型如char、short、long和long long在表19-1中没有列出。你必须确定数据对象的大小并使用相应的例程d例如,short int通常是16位的,而int和long可以是32位或64位,long long是64位的(可以使用第13章介绍的sizeof运算符确定任何数据类型的大小)。所以 要归档shortint的数据,首先将其存储在int中,然后使用encodelntforKey:归档它。反向执行该 过程可恢复它:使用decodelntForKey:,然后将其赋值给short int变量。,19.4 使用NSData创建自定义档案,有时可能不想和前面示例程序一样,使用archiveRootObjectToFile:方法将对象直接写入文件。比如,可能想收集一些或佥部对象,并将其存储到单个档案文件中。在Objective-C中,通过使 用名为NSData的通用数据流对象类,可以实现上述功能,在第16章,我们简单地提到过这个类。,19.4 使用NSData创建自定义档案,正如第16章所提到的,NSData对象可以用来保留一块内存空间以备后来存储敉据。这些数 据空间的典型应用是怍为一些数据的临时存储空间,如随后将被写人文件,或可能用于容纳从 磁盘读取的文件內容。创建可变数据空间的最简单方式是使用data方法,19.4 使用NSData创建自定义档案,dataArea = NSMutabletata date; 该语句创建一个空缓冲区,其大小随程序执行需要而扩展。 作为一个简单的例子,假设你想将地址簿和一个Foo对象归档到同一个文件。假设对于这个 例子,你已经向AddressBook和AddressCard类添加了一个带键的归档方法 参见如下代码,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; 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,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; 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,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 object dataArea = NSMutableData data; archiver = NSKeyedArchiver alloc initForWritingWithMutableData: dataArea; / Now we can begin to archive objects archiver encodeObject: myBook forKey: ”myaddrbook”; archiver encodeObject: myFoo1 forKey: ”myfoo1”; archiver finishEncoding; / Write the archived data are to a file if ( dataArea writeToFile: ”myArchive” atomically: YES = NO) NSLog (”Archiving failed!”); archiver release; myFoo1 release; pool drain; return 0; ,19.4 使用归档程序复制对象,分配一个NSKeyedArchiver对象之后,发送initForWritingWithMutableData:消息,以指定要 写入归档数据的存储空间。这就是前面创建的NSMutabledata空间dataArea。此时,就可以向存储在archives中的NSKeyedArchiver对象发送编码消息,以归档该程序中的对象.实际上,所有 编码消息在收到finishEncoding消息之前都被归档并存储在指定的数据空间内. 这里,有两个对象需要编码-个是地址簿,另一个是Foo对象,对干这些对象可以使 用encodeObject:forKey:,因为在前面你已经为AddressBook、AddressCard和Foo类实现了编码方法和解码方法(理解这个概念很重要) 在归档这两个对象时,向archiver对象发送一条finishEncoding消息。之后,就不能编码其他对象,你需要发送此消息以完成归档过程。,19.4 使用归档程序复制对象,此时,你预留的那块名为dataArea的空间包含归档对象,这些对象可以一种可写入文件的格式存在。消息表达式 data writeToFile: ”myArchive” atomically: YES 向你的数据流发送writeToFile:atomically:消息,请求它把它的数据写人指定文件, 这个文件名为myArchive。 从if语句可以看到writeToFile:atomically:方法返回一个BOOL值:如果写 操作成功就返回YES,如果失败(可能是指定了无效的路径名或文件系统已满)就返回NO。 从档案文件中恢复数据很简单所做的工作只需和归档文件相反,首先,需要像以前那 样分配一个数据空间。然后,把挡案文件中的数据读入该数据空间,然后,需要创建一个 NSKeyedUnarchiver对象,并告知它从指定空间解码数据。必须调用解码方法来提取和解码归 档的对象,做完之后,向NSKeyedUnarchiver对象发送一条finishDecoding消息 代码清单19-10实现了所有任务。,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; NSData *dataArea; NSKeyedUnarchiver *unarchiver; Foo *myFoo1; AddressBook *myBook; / Read in the archive and connect an / NSKeyedUnarchiver object to it dataArea = NSData dataWithContentsOfFile: ”myArchive”;,19.4 使用归档程序复制对象,if (! dataArea) NSLog (“Cant read back archive file!”); Return (1); unarchiver = NSKeyedUnarchiver alloc initForReadingWithData: dataArea; / Decode the objects we previously stored in the archive myBook = unarchiver decodeObjectForKey: ”myaddrbook”; myFoo1 = unarchiver decodeObjectForKey: ”myfoo1”; unarchiver finishDecoding; unarchiver release; / Verify that the restore was successful myBook list; NSLog (“%n%in%g”, myFoo1 strVal, myFoo1 intVal, myFoo1 floatVal); pool release; return 0; ,19.4 使用归档程序复制对象,输出: = Contents of: Steves Address Book = Jamie Baker Julia Kochan Stephen Kochan stevesteve_ Tony Iannino tony.ianni
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 北京市人民医院红细胞血型系统非ABO知识深度考核
- 2025北京第四实验学校招聘45人模拟试卷及一套参考答案详解
- 张家口市人民医院电力安全操作规程基础考核
- 沧州市中医院护理专家终身成就评审
- 沧州市人民医院免疫功能低下患者管理考核
- 大学食堂安全知识培训课件
- 天津市人民医院影像与临床结合考核
- 上海市中医院辅助生殖并发症处理应急考核
- 沧州市中医院财务管理高级研修班结业论文项目评审
- 张家口市人民医院肌病诊断专项考核
- 药食同源培训
- 音乐传播三试题及答案
- 秦朝服饰设计分享
- 子宫脱垂的中医护理查房
- 2024年12月英语四级真题及答案-第1套
- 【课件】急性百草枯农药中毒
- 干部人事档案专项审核工作实施计划方案
- 老年人能力评估师试题【含答案】
- 安徽省蚌埠市2024-2025学年八年级下学期第一次月考地理试卷(含答案)
- 全国小学语文赛课一等奖统编版(2024新编)语文一年级上册《gkh》精美课件
- 《阻燃化学品 焦磷酸哌嗪》文本及编制说明
评论
0/150
提交评论