代码如下:
- NSString *str = @"abc";
- NSString *astr = @"efg";
- NSArray *Array = [NSArray arrayWithObjects:str, astr, nil];
-
-
- NSString *Path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString *filename = [Path stringByAppendingPathComponent:@"test.plist"];
- [NSKeyedArchiver archiveRootObject:Array toFile:filename];
-
- str = @"a";
- astr = @"";
-
-
- NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithFile: filename];
- str = [arr objectAtIndex:0];
- astr = [arr objectAtIndex:1];
-
- NSLog(@"str:%@",str);
- NSLog(@"astr:%@",astr);
下面是一个数据持久化的应用的实例:
开发应用程序时,有一个很好的机会,你会希望有一些持久性的排序(保存名称,密码,分数等)。 NSUserDefaults提供了一个简单的方法来安全地存储信息。然而,你可能需要一个更强大的解决方案。你的逻辑数据抽象不应该有符合的持久性机制的限制,你需要一个解决方案,具有足够的灵活性来归档所有你的对象,不只是字符串,数组和字典。这就是NSKeyed(Un)Archiver的用武之地。
这里的处理:我们为运动教练创建一个。他需要为他的运动员的统计资料归档/检索解决方案。讨论的规格后,我们已经打破了我们的抽象。
我们有一个ScoreCard 类,将举行一个运动员的最佳时机,和所有的分数数组。
我们有一个Athlete类,包含运动员的具体信息,和记分卡实例。
我们有Roster类,包含了一些名册的具体信息,与运动员实例数组一起。
这里是我们简单的类的代码:
-
- #import <Foundation/Foundation.h>
-
- @interface ScoreCard : NSObject <NSCoding> {
-
- NSString *bestTime;
- NSMutableArray *allTimes;
-
- }
-
- @property (copy) NSString *bestTime;
- @property (copy) NSMutableArray *allTimes;
-
-
-
- @end
-
- @implementation ScoreCard
-
- @synthesize bestTime, allTimes;
-
- - (id)init {
-
- if (self = [super init]) {
-
- bestTime = [[NSString alloc] init];
- allTimes = [[NSMutableArray alloc] init];
-
- }
-
- return self;
-
- }
-
- - (id)initWithCoder:(NSCoder *)aDecoder {
-
- if (self = [super init]) {
-
- bestTime = [[aDecoder decodeObjectForKey:@"bestTime"] retain];
- allTimes = [[aDecoder decodeObjectForKey:@"allTimes"] retain];
-
- }
-
- return self;
-
- }
-
- - (void)encodeWithCoder:(NSCoder *)aCoder {
-
- [aCoder encodeObject:bestTime forKey:@"bestTime"];
- [aCoder encodeObject:allTimes forKey:@"allTimes"];
-
- }
-
- - (void)dealloc {
-
- [bestTime release];
- [allTimes release];
- [super dealloc];
-
- }
-
- @end
通过在类里声明两个方法initWithCoder: / encodeWithCoder:,使我们的类符合NSCoding协议---当然我们已经在类里实现了这两个方法。
当ScoreCard 类的对象被encoded时,必须保证它的实例变量也一起被encoded.正如你看到的,ScoreCard对象在[encodeWithCoder:]对此进行了相应处理。
当然在 [initWithCoder:]方法里也做了相应的解码处理。在这里,ScoreCard对象通过NSCoder参数传过来的信息来初始化它的实例变量。这是一个优雅的解决
办法;我们没有必要去关注编码/解码的过程,而ScoreCard从放进去和它的实例变量都能当成常规对象看待。
对于encode/decode方法在什么时候会被唤醒你可能有一些疑问,那么请看接下来我们其它对象的代码,一切都会变得很明了。
-
- #import <Foundation/Foundation.h>
-
- @interface Athlete : NSObject <NSCoding> {
-
- NSString *name;
- NSString *bio;
- NSString *phoneNumber;
- ScoreCard *scoreCard;
- BOOL eligible;
-
- }
-
- @property (copy) NSString *name, *bio, *phoneNumber;
- @property (retain) ScoreCard *scoreCard;
- @property (getter=isEligible) BOOL eligible;
-
- - (void)print;
-
- @end
-
-
- @implementation Athlete
-
- @synthesize name, bio, phoneNumber, scoreCard, eligible;
-
- - (id)init {
-
- if (self = [super init]) {
-
- name = [[NSString alloc] init];
- bio = [[NSString alloc] init];
- phoneNumber = [[NSString alloc] init];
- scoreCard = [[ScoreCard alloc] init];
- eligible = YES;
-
- }
-
- return self;
- }
-
- - (id)initWithCoder:(NSCoder *)aDecoder {
-
- if (self = [super init]) {
-
- name = [[aDecoder decodeObjectForKey:@"name"] retain];
- bio = [[aDecoder decodeObjectForKey:@"bio"] retain];
- phoneNumber = [[aDecoder decodeObjectForKey:@"phoneNumber"] retain];
- scoreCard = [[aDecoder decodeObjectForKey:@"scoreCard"] retain];
- eligible = [aDecoder decodeBoolForKey:@"eligible"];
-
- }
-
- return self;
-
- }
-
- - (void)encodeWithCoder:(NSCoder *)aCoder {
-
- [aCoder encodeObject:name forKey:@"name"];
- [aCoder encodeObject:bio forKey:@"bio"];
- [aCoder encodeObject:phoneNumber forKey:@"phoneNumber"];
- [aCoder encodeObject:scoreCard forKey:@"scoreCard"];
- [aCoder encodeBool:eligible forKey:@"eligible"];
-
- }
-
- - (void)print {
-
- NSLog(@"Name: %@\nBio: %@\nTel: %@\n\nBest Time: %@\n\nAll Times:", name, bio, phoneNumber, [scoreCard bestTime]);
- for (NSString *time in [scoreCard allTimes])
- NSLog(@"%@", time);
-
- }
-
- - (void)dealloc {
-
- [name release];
- [bio release];
- [phoneNumber release];
- [scoreCard release];
- [super dealloc];
-
- }
- @end
实际上这里没有什么新东西,除了新定义了一个BOOL变量外。
只要注意
在
我们的
编码/解码
的方法来处理
这种类型的
原始数据
的微小变化。
我写了一个
快速打印的方法
,所以
我们
可以很容易地
测试程序的输出。
同时,正如你看到的,Athlete对象中包含一个ScoreCard实例变量。当一个Athlete对象encoded/decoded时,ScoreCard实例变量也进行同样的操作(当然所有的实例变量
都会进行这样的操作,我特意指出ScoreCard实例变量只是因为它是一个定制的对象)。
-
- #import <Foundation/Foundation.h>
-
- @interface Roster : NSObject <NSCoding> {
-
- NSMutableArray *athletes;
- int rank;
-
- }
-
- @property (retain) NSMutableArray *athletes;
- @property int rank;
-
- - (void)print;
- - (void)addAthlete:(Athlete *)athlete;
-
- @end
-
- @implementation Roster
-
- @synthesize rank, athletes;
-
- - (id)init {
-
- if (self = [super init]) {
-
- rank = 0;
- athletes = [[NSMutableArray alloc] init];
-
- }
-
- return self;
-
- }
-
- - (id)initWithCoder:(NSCoder *)aDecoder {
-
- if (self = [super init]) {
-
- athletes = [[aDecoder decodeObjectForKey:@"athletes"] retain];
- rank = [aDecoder decodeIntForKey:@"rank"];
-
- }
-
- return self;
-
- }
-
- - (void)encodeWithCoder:(NSCoder *)aCoder {
-
- [aCoder encodeObject:athletes forKey:@"athletes"];
- [aCoder encodeInt:rank forKey:@"rank"];
-
- }
-
- - (void)addAthlete:(Athlete *)athlete {
-
- [athletes addObject:athlete];
-
- }
-
- - (void)print {
-
- NSLog(@"Roster info:\nRank: %d", rank);
- for (Athlete *athlete in athletes)
- NSLog(@"%@", [athlete name]);
-
- }
-
- - (void)dealloc {
-
- [athletes release];
- [super dealloc];
- }
-
- @end
这里,同样的处理;这次我负责初始化和打印选手名字的工作。
现在运行测试.
- static NSString *names [] = { @"Jeff Beck", @"Eric Clapton", @"Angus Young", @"John Doe", @"Jane Doe", @"Shaun White", @"Flavius Josephus" };
-
-
- Roster * create() {
-
- NSMutableArray *scoresArray = [NSMutableArray arrayWithObjects:@"15:09:34", @"17:54:01", @"19:56:08", nil];
-
- Roster *roster = [[Roster alloc] init];
- for (int i = 0; i < 7; ++i) {
-
- Athlete *athlete = [[Athlete alloc] init];
- [athlete setName:names[i]];
- [athlete setBio:@"I'm a boss"];
- [athlete setPhoneNumber:@"867-5309"];
- [athlete.scoreCard setBestTime:@"12:30:34"];
- [athlete.scoreCard setAllTimes:scoresArray];
-
- [roster addAthlete:athlete];
-
- }
-
- return [roster autorelease];
-
- }
-
- int main (int argc, char **argv) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
-
- Roster *roster = create();
- [NSKeyedArchiver archiveRootObject:roster toFile:@"/roster.archive"];
-
-
-
-
-
-
-
-
-
- [pool drain];
- return 0;
- }
程序第一次运行时,一个Roster对象被创建,填充和存档。
去除下面几行的注释,你就可心从档案里创建一个Roster对象。