代码如下:
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类,包含了一些名册的具体信息,与运动员实例数组一起。
这里是我们简单的类的代码:
// ScoreCard.h #import <Foundation/Foundation.h> @interface ScoreCard : NSObject <NSCoding> { NSString *bestTime; NSMutableArray *allTimes; } @property (copy) NSString *bestTime; @property (copy) NSMutableArray *allTimes; // other methods not relevant to this tutorial go here @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:]方法里也做了相应的解码处理。在这里,ScoreCard对象通过NSCoder参数传过来的信息来初始化它的实例变量。这是一个优雅的解决
办法;我们没有必要去关注编码/解码的过程,而ScoreCard从放进去和它的实例变量都能当成常规对象看待。
对于encode/decode方法在什么时候会被唤醒你可能有一些疑问,那么请看接下来我们其它对象的代码,一切都会变得很明了。
// Athlete.h #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
都会进行这样的操作,我特意指出ScoreCard实例变量只是因为它是一个定制的对象)。
// Roster.h #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" }; // function to create a roster. in real life, this wouldn't be used, but we're just testing now 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]; // create and archive a roster Roster *roster = create(); [NSKeyedArchiver archiveRootObject:roster toFile:@"/roster.archive"]; // unarchive roster // Roster *roster = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/roster.archive"]; // // [roster print]; // // for (Athlete *athlete in [roster athletes]) // [athlete print]; [pool drain]; return 0; }