归档这部分内容,又三个基本知识点:使用XML属性列表进行归档、使用NSKeyedArchiver归档、使用NSData创建自定义档案。
一、使用XML属性列表进行归档
使用XML进行归档,前提是你的对象是NSString、NSDictionary、NSArray、NSData或NSNumber类型,你可以使用他们共有的一个方法writeToFile:atmically:将数据写到文件中,该方法可以使用XML属性列表的格式写出数据。
writeToFile:atmically:方法的一个参数是你要写入的文件路径,你没必要自己创建一个文件,如果系统找不到,会自动创建。第二个参数是一个布尔值,如果为YES,是希望首先将要保存的对象写入临时备份文件中,一旦成功,紧接着会将数据转移到你要创建的文件中,这是一种安全措施。
下面通过一个例子来使用一下:
//使用XML进行归档
//写入data文件
NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:@"she is a beautiful girl!",@"girl",@"he is a hasome man!",@"man",@"i don‘t know who you are!",@"gay", nil];
if ([data writeToFile:@"data" atomically:YES] == NO) {
NSLog(@"Save to file failed!");
}
NSLog(@"%@",[[NSFileManager defaultManager] currentDirectoryPath]);
//读取data文件
NSDictionary *data2 = [NSDictionary dictionaryWithContentsOfFile:@"data"];
for (NSString *key in data2) {
NSLog(@"%@: %@",key,[data2 objectForKey:key]);
}
//写入data3文件
NSString *data3 = @"i'm data file!";
if ([data3 writeToFile:@"data3" atomically:YES encoding:NSUTF8StringEncoding error:nil] == NO) {
NSLog(@"Save to file failed!");
}
//读取data3文件
NSString *str = [NSString stringWithContentsOfFile:@"data3" encoding:NSUTF8StringEncoding error:nil];
NSLog(@"%@",str);
二、使用NSKeyedArchiver归档
对于上面的例子我们可以使用NSKeyedArchiver进行同样的归档,如下:
NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:@"she is a beautiful girl!",@"girl",@"he is a hasome man!",@"man",@"i don‘t know who you are!",@"gay", nil];
if ([NSKeyedArchiver archiveRootObject:data toFile:@"data"] == NO) {
NSLog(@"archiving failed!");
}
NSDictionary *data2 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"data"];
for (NSString *key in data2) {
NSLog(@"%@:%@",key,[data2 objectForKey:key]);
}
上面的例子我们使用了NSKeyedArchiver类和NSKeyedUnarchiver类的相应的方法存入和读取数据,很简单吧,但是它也是用于 NSString、NSDictionary、NSArray、NSData或NSNumber之类的基本OC类对象,如果我们要储存我们自定义的类的数据就不是这么简单了。这里要用到<NSCoding>协议,要在自定义类里实现encodeWithCoder:方法和initWithCoder:方法。
在说明如何实现这两个方法之前,先解释一下NSKeyedArchiver类和NSKeyedUnarchiver类是如何进行归档的:
我们调用NSKeyedArchiver类的方法archiveRootObject:toFile:的时候,其实就是创建了一个带键的文档,在这个文档中,每个归档字段都有一个名称,归档某个对象的时候,会为他提供一个名称,即键。所以,当我们读取数据的时候是通过这个键来获取响应内容。
我们自定义的类如何将数据交给NSKeyedArchiver类让它写入文件中呢?我们通过协议,实现initWithCoder:方法,将数据交给NSKeyedArchiver类并写入文件中,并通过encodeWithCoder:方法来获取存入的数据。如下面的自定义例子:
自定义类MyCard:
.h文件:
#import <Foundation/Foundation.h>
@interface MyCard : NSObject <NSCoding>
{
int myAge;
}
@property (copy,nonatomic) NSString *myName;
@property int myAge;
@end
.m文件:
#import "MyCard.h"
@implementation MyCard
@synthesize myName,myAge;
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:myName forKey:@"name"];
[aCoder encodeInt:myAge forKey:@"age"];
}
-(id) initWithCoder:(NSCoder *)aDecoder
{
myName = [aDecoder decodeObjectForKey:@"name"];
myAge = [aDecoder decodeIntForKey:@"age"];
return self;
}
@end
main文件中写入:
//自定义类使用NSKeyedArchiver归档
//写入文件
MyCard *card1 = [[MyCard alloc] init];
card1.myName = @"张三";
card1.myAge = 100;
if ([NSKeyedArchiver archiveRootObject:card1 toFile:@"card.arch"] == NO) {
NSLog(@"archiving failed!");
}
//读取文件
MyCard *card2 = [NSKeyedUnarchiver unarchiveObjectWithFile:@"card.arch"];
NSLog(@"myName:%@ myAge:%i",card2.myName,card2.myAge);
这样就实现了自定义类数据存储和读取。我们通过传递一个人NSCoder类对象,对自定义类的数据进行编码和解码。下面列出在带键的档案中编码和解码基本数据类型:
编码方法:解码方法:
encodeBool:forKey:decodeBool:forKey:
encodeInt:forKey:decodeInt:forKey:
encodeInt32:forKey:decodeInt32:forKey:
encodeInt64:forKey:decodeInt64:forKey:
encodeFloat:forKey:decodeFloat:forKey:
encodeDouble:forKey:decodeDouble:forKey:
三、使用NSData创建自定义档案
如果我们不想像上面的例子那样只能把一个类的数据储存在一个文件中,而是想将收集到的多个类的数据储存到一个文件中,我们可以通过NSData通用数据流对象类实现这个功能。NSData对象可以用来保留一块内存空间,以备将来存储数据。如下例子:
//写入文件
MyCard *card1 = [[MyCard alloc] init];
card1.myName = @"张三";
card1.myAge = 100;
MyCard *card2 = [[MyCard alloc] init];
card2.myName = @"李四";
card2.myAge = 50;
//创建一个空的可变的NSMutableData对象,也叫设置一个空的数据区
NSMutableData *dataArea = [NSMutableData data];
//指定dataArea为写入归档数据的储存空间
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:dataArea];
//开始写入要存储对象的数据
[archiver encodeObject:card1 forKey:@"card1"];
[archiver encodeObject:card2 forKey:@"card2"];
[archiver finishEncoding]; //结束写入
if ([dataArea writeToFile:@"myArchive" atomically:YES] == NO) {
NSLog(@"archiving failed!");
}
//读取文件
NSData *dataArea2 = [NSData dataWithContentsOfFile:@"myArchive"];
if (! dataArea2) {
NSLog(@"can't read back archive file");
return 1;
}
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:dataArea2];
//解码存储在归档文件中的数据
MyCard *card3 = [unarchiver decodeObjectForKey:@"card1"];
MyCard *card4 = [unarchiver decodeObjectForKey:@"card2"];
//检验是否成功
NSLog(@"card3.myName:%@",card3.myName);
NSLog(@"card4.myName:%@",card4.myName);