Objective-C2.0程序设计第19章-归档.ppt_第1页
Objective-C2.0程序设计第19章-归档.ppt_第2页
Objective-C2.0程序设计第19章-归档.ppt_第3页
Objective-C2.0程序设计第19章-归档.ppt_第4页
Objective-C2.0程序设计第19章-归档.ppt_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第19章归档,目录,19.1使用XML属性列表进行归档19.2使用NSKeyedArchiver归档19.3编码方法和解码方法19.4使用NSData创建自定义档案19.5使用归档程序复制对象,19.1使用XML属性列表进行归档,MacOSX上的应用程序使用XML属性列表(或plists)来存储诸如默认参数选择、应用程序设置和配置信息这样的数据,因此,了解如何创建和读回这些数据很有用。然而,这些列表的归档用途是有限的,因为当为某个数据结构创建属性列表时,没有保存特定的对象类,没有存储对同一对象的多个引用,也没有保持对象的可变性。,19.1使用XML属性列表进行归档,如果你的对象是NSString、NSDictionary,NSArray、NSData或NSNumber对象,你可以使用在这些类中实现的writeToFile:atomically:方法将数据写到文件中。在写出某个字典或数组的情况下,该方法可以使用XML厲性列衷的格式写出数据。代码清单19-1显示了如何将在第15章“数字、字符串和集合“中作为简易术语表而创建的字典作为属性列表写入文件中。,19.1使用XML属性列表进行归档,#import#import#import#importintmain(intargc,char*argv)NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;NSDictionary*glossary=NSDictionarydictionaryWithObjectsAndKeys:”Aclassdefinedsootherclassescaninheritfromit.”,”abstractclass”,”Toimplementallthemethodsdefinedinaprotocol”,”adopt”,”Storinganobjectforlateruse.“,”archiving”,nil;if(glossarywriteToFile:”glossary”atomically:YES=NO)NSLog(”Savetofilefailed!”);pooldrain;return0;,19.1使用XML属性列表进行归档,writeToFile:atomically:消息被发送给字典对象glossary,使字典以属性列表的形式写到文件glossary中,atomically参数被设为YES,表示希望首先将字典写入临时备份文件中,并且一且成功,将把最终数据转移到名为glossary的指定文件中。这是一种安全措施,它保护文件在一些情况下(如系统在执行操作的过程中崩溃时)免受破坏。在这种情况下,原始的glossary文件(如果该文件已存在)不会受到损害。如果查看代码淸单19-1中创建的glossary文件,它的内容可能如下:,19.1使用XML属性列表进行归档,abstractclassAclassdefinedsootherclassescaninheritfromit.adoptToimplementallthemethodsdefinedinaprotocolarchivingStoringanobjectforlateruse.,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#importintmain(intargc,char*argv)NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;NSDictionary*glossary;glossary=NSDictionarydictionaryWithContentsOfFile:”glossary”;for(NSString*keyinglossary)NSLog(”%:%”,key,glossaryobjectForKey:key);pooldrain;return0;输出:archiving:Storinganobjectforlateruse.abstractclass:Aclassdefinedsootherclassescaninheritfromit.adopt:Toimplementallthemethodsdefinedinaprotocol,19.1使用XML属性列表进行归档,你的属性列表不必从Objective-C程序中创建,属性列表可以来自任何的源。可以使用简单的文本编辑器,或使用MacOSX系统中位于/Developer/Applications/Utilities目录下的PropertyListEditor程序来创建属性列表。,19.2使用NSKeyedArchiver归档,在带键的档案中,每个归档字段都有一个名称。归档某个对象时,会为它提供一个名称,即键。从归档中检索该对象时,是根据这个键来检索它的。这样,可以按照任意的顺序将对象写人归档井进行检素。另外,如果向类添加了新的实例变量或删除了实例变量,程序也可以进行处理。代码清单19-3展示了如何使用NSKeyedArchiver类中的archiveRootObject:toFile:方法将glossary存储到磁盘上,要使用该类,在你的程序中包含以下文件#import,19.2使用NSKeyedArchiver归档,#import#import#import#import#importintmain(intargc,char*argv)NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;NSDictionary*glossary=NSDictionarydictionaryWithObjectsAndKeys:”Aclassdefinedsootherclassescaninheritfromit”,”abstractclass”,”Toimplementallthemethodsdefinedinaprotocol”,”adopt”,”Storinganobjectforlateruse”,”archiving”,nil;NSKeyedArchiverarchiveRootObject:glossarytoFile:”glossary.archive”;poolrelease;return0;,19.2使用NSKeyedArchiver归档,代码淸单19-3并不在终端产生任何输出,但是语句NSKeyedArchiverarchiveRootObject:glossarytoFile:”glossary.archive”;将字典glossary写入文件glossary.archive中。可以为该文件指定任何路径名,在本例中,文件被写入当前目录下。以后通过NSKeyedUuarchiver的unArChiveObjectWithFile:方法将创建的归档文件读人执行程序中,如代码清单19-4所示。#import#import#import#import#import#importintmain(intargc,char*argv)NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;NSDictionary*glossary;glossary=NSKeyedUnarchiverunarchiveObjectWithFile:”glossary.archive”;for(NSString*keyinglossary)NSLog(”%:%”,key,glossaryobjectForKey:key);pooldrain;return0;,19.2使用NSKeyedArchiver归档,19.4输出:abstractclass:Aclassdefinedsootherclassescaninheritfromit.adopt:Toimplementallthemethodsdefinedinaprotocolarchiving:Storinganobjectforlateruse.语句;glossary=NSKeyedUnarchiverunarchiveObjectWithFile:”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#importinterfaceAddressCard:NSObjectNSString*name;NSString*email;property(copy,nonatomic)NSString*name,*email;-(void)setName:(NSString*)theNameandEmail:(NSString*)theEmail;-(NSComparisonResult)compareNames:(id)element;-(void)print;/AdditionalmethodsforNSCopyingprotocol-(AddressCard*)copyWithZone:(NSZone*)zone;-(void)retainName:(NSString*)theNameandEmail:(NSString*)theEmail;end,19.3编码方法和解码方法,下面是要添加到AddressCard类实现文件的两个新方法:-(void)encodeWithCoder:(NSCoder*)encoderencoderencodeObject:nameforKey:”AddressCardName”;encoderencodeObject:emailforKey:”AddressCardEmail”;-(id)initWithCoder:(NSCoder*)decodername=decoderdecodeObjectforKey:”AddressCardName”retain;email=decoderdecodeObjectforKey:”AddressCardEmail”retain;returnself;,19.3编码方法和解码方法,该程序向编码方法encodeWithCoder:传人一个NSCoder对象作为参数。由干AddressCard类直接继承自Nsobject,所以无需担心编码继承的实例变量。如果的确担心,并且知道类的子类符合NSCoding协议的要求,那么应该用下面的语句开始编码方法,确保继承的实例变量也被编码:superencodeWithCoder:encoder;,19.3编码方法和解码方法,对于地址簿来说,有两个名为name和email的实例变量。因为它们都是NSString对象,所以使用encodeObjectiforKey:方法依次对它们进行编码,然后将这两个实例变量添加到归档文件中。encodeObjectforKey:方法编码对象并将其存储在指定的键下,以后可使用该键检索对象。键名是任意的,所以只要在检索(编码)数据时使用的名称与归档(编码)时使用的名称相同,就可以指定任何键名。唯一可能出现冲突的情况是,为正在编码的对象子类使用了相同的键。为了防止这种情况出现,制订归档的键时,可将类名放在实例变量名的前面,代码淸单19-5就是这样做的。,19.3编码方法和解码方法,注意,encodeObjectForKey:方法可以用于任何在其类中实现对应encodeWithCoder:方法的对象.解码的过程刚好相反。传递给initWithCoder的参数也是NSCoder对象,不必担心这个参数,只要记住它是获得该消息(对于每个想要从归档文件中提取的对象)的对象。同样,由于AddressCard类直接继承自NSObject,所以不必担心解码继承的实例变i。如果的确担心,那么应在解码方法的开始插人下列行(假设类的超类符合NSCoding协议的要求):self=superinitwithCoder:decoder;通过调用decodeObjectforKey:方法并传递在编码变量时使用的相同键,就可解码每个实例变量。类似于AddressCard类,你为AddressBook类添加了两个编码和解码方法。在接口文件中只需更改指令,以声明现在AddressBook类已经符合NSCoding协议。更改如下所示:interfaceAddressBook:NSObject,19.3编码方法和解码方法,下面是实现文件中所含的方法定义:-(void)encodeWithCoder:(NSCoder*)encoderencoderencodeObject:bookNameforKey:“AddressBookBookName”;encoderencodeObject:bookforKey:”AddressBookBook”;-(id)initWithCoder:(NSCoder*)decoderbookName=decoderdecodeObjectForKey:”AddressBookBookName”retain;book=decoderdecodeObjectForKey:”AddressBookBook”retain;returnself;以下代码清单19-6是它的测试程序。,19.3编码方法和解码方法,#import“AddressBook.h”#importintmain(intargc,char*argv)NSString*aName=”JuliaKochan”;NSString*aEmail=”jewls337”;NSString*bName=”TonyIannino”;NSString*bEmail=”tony.iannino”;NSString*cName=”StephenKochan”;NSString*cEmail=”stevesteve_”;NSString*dName=”JamieBaker”;NSString*dEmail=”jbaker”;NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;AddressCard*card1=AddressCardallocinit;AddressCard*card2=AddressCardallocinit;AddressCard*card3=AddressCardallocinit;AddressCard*card4=AddressCardallocinit;AddressBook*myBook=AddressBookalloc;/Firstsetupfouraddresscardscard1setName:aNameandEmail:aEmail;card2setName:bNameandEmail:bEmail;card3setName:cNameandEmail:cEmail;card4setName:dNameandEmail:dEmail;myBook=myBookinitWithName:”StevesAddressBook”;,19.3编码方法和解码方法,/AddsomecardstotheaddressbookmyBookaddCard:card1;myBookaddCard:card2;myBookaddCard:card3;myBookaddCard:card4;myBooksort;if(NSKeyedArchiverarchiveRootObject:myBooktoFile:”addrbook.arch”=NO)NSLog(”archivingfailed”);card1release;card2release;card3release;card4release;myBookrelease;pooldrain;return0;这个程序创建了一个地址簿,然后将它归档到文件addrbook.arch中。在创建归档文件的过程中,注意AddressBook类和AddressCard类中的编码方法都被调用了。如果想要验证,可以向这些方法添加一些NSLog调用。,19.3编码方法和解码方法,代码淸单19-7展示了如何将归档读人内存以根据文件创建地址簿。#import“AddressBook.h”#importintmain(intargc,char*argv)AddressBook*myBook;NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;myBook=NSKeyedUnarchiverunarchiveObjectWithFile:”addrbook.arch”;myBooklist;pooldrain;return0;输出:=Contentsof:StevesAddressBook=JamieBakerjbakerJuliaKochanjewls337StephenKochanstevesteve_TonyIanninotony.iannino=,19.3编码方法和解码方法,在解码地址簿的过程中,自动调用向两个类添加的解码方法。注意将地址薄读回程序是多么容易。前面说过,encodeObject:forKey:方法作用子内置类以及根据NSCoding协议为其编写编码和解码方法的类。如果你的实例包含基本数据类型,如整型或浮点型,那么需要知道如何对它们进行编码和解码(参见表19-1)。下面是一个类的简单定义,这个类名为Foo,它包含三个实例变量:一个是NSString类型,一个int型,一个float型。这个类包含一个赋值方法、三个取值方法以及两个用于归档的编码/解码方法:interfaceFoo:NSObjectNSString*strVal;intintVal;floatfloatVal;property(copy,nonatomic)NSString*strVal;propertyintintVal;propertyfloatfloatVal;end,19.3编码方法和解码方法,实现文件如下:implementationFoosynthesizestrVal,intVal,floatVal;-(void)encodeWithCoder:(NSCoder*)encoderencoderencodeObject:strValforKey:”FoostrVal”;encoderencodeInt:intValforKey:”FoointVal”;encoderencodeFloat:floatValforKey:”FoofloatVal”;-(id)initWithCoder:(NSCoder*)decoderstrVal=decoderdecodeObjectForKey:”FoostrVal”retain;intVal=decoderdecodeIntForKey:”FoointVal”;floatVal=decoderdecodeFloatForKey:”FoofloatVal”;returnself;end,19.3编码方法和解码方法,编码例程首先使用前面用过的encodeObject:forKey:对象来编码字符串值strVal如上面内容所示。在代码淸单19-8中,我们创建了一个Foo对象,把它归档到一个文件,解归档,然后显示。,19.3编码方法和解码方法,#import#import#import#import#import“Foo.h”/DefinitionforourFooclassintmain(intargc,char*argv)NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;Foo*myFoo1=Fooallocinit;Foo*myFoo2;myFoo1setStrVal:”Thisisthestring”;myFoo1setIntVal:12345;myFoo1setFloatVal:98.6;NSKeyedArchiverarchiveRootObject:myFoo1toFile:”foo.arch”;myFoo2=NSKeyedUnarchiverunarchiveObjectWithFile:”foo.arch”;NSLog(”%n%in%g”,myFoo2strVal,myFoo2intVal,myFoo2floatVal);myFoo1release;pooldrain;return0;输出:Thisisthestring1234598.6,19.3编码方法和解码方法,以下消息归档了对象的3个实例变量:encoderencodeObject:strValforKey:”FoostrVal”;encoderencodeInt:intValforKey:”FoointVal”;encoderencodeFloat:floatValforKey:”FoofloatVal”;一些基本数据类型如char、short、long和longlong在表19-1中没有列出。你必须确定数据对象的大小并使用相应的例程d例如,shortint通常是16位的,而int和long可以是32位或64位,longlong是64位的(可以使用第13章介绍的sizeof运算符确定任何数据类型的大小)。所以要归档shortint的数据,首先将其存储在int中,然后使用encodelntforKey:归档它。反向执行该过程可恢复它:使用decodelntForKey:,然后将其赋值给shortint变量。,19.4使用NSData创建自定义档案,有时可能不想和前面示例程序一样,使用archiveRootObjectToFile:方法将对象直接写入文件。比如,可能想收集一些或佥部对象,并将其存储到单个档案文件中。在Objective-C中,通过使用名为NSData的通用数据流对象类,可以实现上述功能,在第16章,我们简单地提到过这个类。,19.4使用NSData创建自定义档案,正如第16章所提到的,NSData对象可以用来保留一块内存空间以备后来存储敉据。这些数据空间的典型应用是怍为一些数据的临时存储空间,如随后将被写人文件,或可能用于容纳从磁盘读取的文件內容。创建可变数据空间的最简单方式是使用data方法,19.4使用NSData创建自定义档案,dataArea=NSMutabletatadate;该语句创建一个空缓冲区,其大小随程序执行需要而扩展。作为一个简单的例子,假设你想将地址簿和一个Foo对象归档到同一个文件。假设对于这个例子,你已经向AddressBook和AddressCard类添加了一个带键的归档方法参见如下代码,19.4使用NSData创建自定义档案,#import#import#import#import#import#import#import“AddressBook.h”#import“Foo.h”intmain(intargc,char*argv)NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;Foo*myFoo1=Fooallocinit;Foo*myFoo2;NSMutableData*dataArea;NSKeyedArchiver*archiver;AddressBook*myBook;/InsertcodefromProgram19.7tocreateanAddressBook/inmyBookcontainingfouraddresscards,19.4使用NSData创建自定义档案,#import#import#import#import#import#import#import“AddressBook.h”#import“Foo.h”intmain(intargc,char*argv)NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;Foo*myFoo1=Fooallocinit;Foo*myFoo2;NSMutableData*dataArea;NSKeyedArchiver*archiver;AddressBook*myBook;/InsertcodefromProgram19.7tocreateanAddressBook/inmyBookcontainingfouraddresscards,19.4使用NSData创建自定义档案,myFoo1setStrVal:”Thisisthestring”;myFoo1setIntVal:12345;myFoo1setFloatVal:98.6;/SetupadataareaandconnectittoanNSKeyedArchiverobjectdataArea=NSMutableDatadata;archiver=NSKeyedArchiverallocinitForWritingWithMutableData:dataArea;/NowwecanbegintoarchiveobjectsarchiverencodeObject:myBookforKey:”myaddrbook”;archiverencodeObject:myFoo1forKey:”myfoo1”;archiverfinishEncoding;/Writethearchiveddataaretoafileif(dataAreawriteToFile:”myArchive”atomically:YES=NO)NSLog(”Archivingfailed!”);archiverrelease;myFoo1release;pooldrain;return0;,19.4使用归档程序复制对象,分配一个NSKeyedArchiver对象之后,发送initForWritingWithMutableData:消息,以指定要写入归档数据的存储空间。这就是前面创建的NSMutabledata空间dataArea。此时,就可以向存储在archives中的NSKeyedArchiver对象发送编码消息,以归档该程序中的对象.实际上,所有编码消息在收到finishEncoding消息之前都被归档并存储在指定的数据空间内.这里,有两个对象需要编码-个是地址簿,另一个是Foo对象,对干这些对象可以使用encodeObject:forKey:,因为在前面你已经为AddressBook、AddressCard和Foo类实现了编码方法和解码方法(理解这个概念很重要)在归档这两个对象时,向archiver对象发送一条finishEncoding消息。之后,就不能编码其他对象,你需要发送此消息以完成归档过程。,19.4使用归档程序复制对象,此时,你预留的那块名为dataArea的空间包含归档对象,这些对象可以一种可写入文件的格式存在。消息表达式datawriteToFile:”myArchive”atomically:YES向你的数据流发送writeToFile:atomically:消息,请求它把它的数据写人指定文件,这个文件名为myArchive。从if语句可以看到writeToFile:atomically:方法返回一个BOOL值:如果写操作成功就返回YES,如果失败(可能是指定了无效的路径名或文件系统已满)就返回NO。从档案文件中恢复数据很简单所做的工作只需和归档文件相反,首先,需要像以前那样分配一个数据空间。然后,把挡案文件中的数据读入该数据空间,然后,需要创建一个NSKeyedUnarchiver对象,并告知它从指定空间解码数据。必须调用解码方法来提取和解码归档的对象,做完之后,向NSKeyedUnarchiver对象发送一条finishDecoding消息代码清单19-10实现了所有任务。,19.4使用归档程序复制对象,Program19.10#import#import#import#import#import#import#import“AddressBook.h”#import“Foo.h”intmain(intargc,char*argv)NSAutoreleasePool*pool=NSAutoreleasePoolallocinit;NSData*dataArea;NSKeyedUnarchiver*unarchiver;Foo*myFoo1;AddressBook*myBook;/Readinthearchiveandconnectan/NSKeyedUnarchiverobjecttoitdataArea=NSDatadataWithContentsOfFile:”myArchive”;,19.4使用归档程序复制对象,if(!dataArea)NSLog(“Cantreadbackarchivefile!”);Return(1);unarchiver=NSKeyedUnarchiverallocinitForReadingWithData:dataArea;/DecodetheobjectswepreviouslystoredinthearchivemyBook=unarchiverdecodeObjectForKey:”myaddrbook”;myFoo1=unarchiverdecodeObjectForKey:”myfoo1”;unarchiverfinishDecoding;unarchiverrelease;/VerifythattherestorewassuccessfulmyBooklist;NSLog(“%n%in%g”,myFoo1strVal,myFoo1intVal,myFoo1floatVal);poolrelease;return0;,19.4使用归档程序复制对象,输出:=Contentsof:StevesAddressBook=JamieBakerjbakerJuliaKochanjewls337StephenKochanstevesteve_TonyIanninotony.iannino

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论