“归档”是指用某种格式来保存一个或多个对象,以便以后还原这些对象的过程。
只要在类中实现的每个属性都是标量(如int或flloat)或都是符合NSCoding协议的某个类的实例,就可以对你的对象进行完整归档。
1. NSCoding协议之编码与解码
要进行归档的对象必须符合NSCoding协议。NSCoding协议声明了两个方法,这两个方法都是必须的,分别是:方法encodeWithCoder:将对象编码到归档中;方法initWithCoder:通过对归档解码来创建一个新对象。
编码解码方法都应该指定如何归档想要保存的对象中的每个实例变量。
对于基本Objective-C类(包括NSString、NSArray、NSDictionary、NSSet、NSDate、NSNumber和NSData等)以及嵌套的对象(如包含字符串,甚至其他数组对象的数组)可以使用 encodeObject:forkey: 方法进行编码,使用initWithCoder:方法进行解码。
对于基本数据类型,可以使用如下表所示的方法进行编码解码:
编码方法 | 解码方法 |
encodeBool:forKey: | decodeBool:forKey: |
encodeInt:forKey: | decodeInt:forKey: |
encodeInt32:forKey: | decodeInt32:forKey: |
encodeInt64:forKey: | decodeInt64:forKey: |
encodeFloat:forKey: | decodeFloat:forKey: |
encodeDouble:forKey: | decodeDouble:forKey: |
示例代码如下:
// 编码方法
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:objectOne forKey:@"keyOfObjectOne"];
[coder encodeObject:objectTwo forKey:@"keyOfObjectTwo"];
[coder encodeInt:someInt forKey:@"keySomeInt"];
[coder encodeFloat:someFloat forKey:@"keyOfSomeFloat"];
}
// 如果超类也遵循NSCoding协议,编码方法还需要确保对超类调用encodeWithCoder:
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:objectOne forKey:@"keyOfObjectOne"];
[coder encodeObject:objectTwo forKey:@"keyOfObjectTwo"];
[coder encodeInt:someInt forKey:@"keySomeInt"];
[coder encodeFloat:someFloat forKey:@"keyOfSomeFloat"];
[super encodeWithCoder:encoder];
}
// 解码方法
- (id)initWithCoder:(NSCoder *)coder {
if (self = [super init]) {
self.objectOne = [coder decodeObjectForKey:@"keyOfObjectOne"];
self.objectTwo = [coder decodeObjectForKey:@"keyOfObjectTwo"];
self.someInt = [coder decodeObjectForKey:@"keySomeInt"];
self.someFloat = [coder decodeObjectForKey:@"keyOfSomeFloat"];
}
return self;
}
2. 归档方式
方式一:
使用NSKeyedArchiver类的类方法archiveRootObject:toFile进行归档;
使用NSKeyedUnarchiver类的类方法unarchiveObjectWithFile:进行解归档。
方式二:
使用NSData创建自定义档案。
NSData对象可以用来保留一块内存空间以备后来存储数据,这些数据空间的典型应用是作为一些数据的临时存储空间,如随后将被写入文件,或可能用于容纳磁盘读取的文件内容。
从符合NSCoding的一个或多个对象创建归档步骤如下:
NSString *filePath = [self dataFilePath:archiveFilePath];
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
initForWritingWithMutableData:data];
[archiver encodeObject:myObject forKey:keyOfMyObject];
[archiver finishEncoding];
[data writeToFile:filePath atomically:YES];
[archiver release];
[data release];
解归档的步骤如下:
NSString *filePath = [self dataFilePath:archiveFilePath];
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]
initForReadingWithData:data];
classOfMyObject *myObject = [unarchiver decodeObjectForKey: keyOfMyObject];
[unarchiver finishDecoding];
[unarchiver release];
[data release];
3. 使用归档来复制对象
归档和解归档过程中产生的是对象的新副本,因此,当需要生成一个对象(或不支持NSCopying协议的对象)的深复制时,应该记住这项技术。
例如对dataArray进行深复制: NSData * data;
data = [NSKeyedArchiver archivedDataWithRootObject:dataArray];
dataArray2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
4. NSCopying协议
符合NSCopying对于任何数据模型对象来说都是一个非常好的主意。NSCopying有一个copyWithZone:方法,可用于复制对象。该方法的内容类似于以下内容:- (id)copyWithZone:(NSZone *)zone {
MyClass * copy = [[[self class] allocWithZone:zone] init];
copy.objectOne = [self.objectOne copyWithZone:zone];
copy.objectTwo = [self.objectTwo copyWithZone:zone];
copy.someInt = self.someInt;
copy.someFloat = self.someFloat;
return copy;
}