NSCoding
1、为了将应用数据存储到硬盘中,iOS提供基本的文件API、Property List序列化、SQLite、CoreData以及NSCoding。对于轻量级的数据要求,NSCoding因其简单而成为一种比较合适的方式。 NSCoding是一个你需要在数据类上要实现的协议以支持数据类和数据流间的编码和解码。数据流可以持久化到硬盘。
2、是类对象本身数据的写入到本地文件。
我 们需要实现两个方法: encodeWithCoder和initWithEncoder。encodeWithCoder就是编码,initWithCoder就是解码。 encodeWithCoder方法传入的是一个NSCoder对象,实现的时候我们就可以调用encodeObject、encodeFloat、 encodeInt等各种方法并通过指定键值进行编码。
对模型对象进行归档
在Cocoa世界中,归档(archiving)是指另一种形式的序列化,但它是任何对象都可以实现的更常规的类型。专门编写用于保存数据的任何模型对象都应该支持归档。使用对模型对象进行归档的技术可以轻松将复杂的对象写入文件,然后再从中读取它们。
只要在类中实现的每个属性都是标量(int.float)或是遵循NSCoding协议的某个类的实例,你就可以对整个对象进行完全的归档。由于大多数支持存储数据的Foundation和Cocoa Touch类都遵循NSCoding协议(除UIImage)。
还有一个协议应该和NSCoding协议一起实现,那就是NSCopying协议。后者允许复制对象,这使你在使用数据模型对象时具备了较大的灵活性。
遵循NSCoding协议
NSCoding协议声明了两个方法,这两个方法都是必需的。一个方法将对象编码到归档中,另一个方法对归档解码来创建一个新对象。
- (void)encodeWithCoder:(NSCoder *)aCoder;
- (instancetype)initWithCoder:(NSCoder *)aDecoder;
这两个方法都传递一个NSCoder实例,使用方法和NSUserDefaults相似。也可以使用KVC对对象和原生数据类型(int,float)进行编码和解码
遵循NSCoding协议
NSCoding协议声明了两个方法,这两个方法都是必需的。一个方法将对象编码到归档中,另一个方法对归档解码来创建一个新对象。这两个方法都传递一个NSCoder实例,使用方法和NSUserDefaults相似。也可以使用KVC对对象和原生数据类型(int,float)进行编码和解码。
对某个对象进行编码的方法可能看起来如下:
(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:foo forKey:kFooKey];
[aCoder encodeObject:bar forKey:kBarKey];
[aCoder encodeInt:someInt forKey:kSomeIntKey];
[aCoder encodeFloat:someFloat forKey:kSomeFloat];
}
若要我们在项目中支持归档,必须使用正确的编码方法将所有实例变量编码成encoder。
如果要子类化某个也遵循NSCoding的类,还需要确保对超类调用 encodeWithCoder: 方法,你的方法将如下所示:(void)encodeWithCoder:(NSCoder *)aCoder{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:foo forKey:kFooKey];
[aCoder encodeObject:bar forKey:kBarKey];
[aCoder encodeInt:someInt forKey:kSomeIntKey];
[aCoder encodeFloat:someFloat forKey:kSomeFloat];
}
我们还需要实现一个通过NSCoder解码的对象初始化方法,恢复我们之前归档的对象。实现initWithCoder:方法比实现encodeWithCoder:方法稍微复杂一些。
如果直接对NSObject进行子类化,或者对某些不遵循NSCoding的其他类进行子类化,则你的方法看起来如下
(instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
foo = [aDecoder decodeObjectForKey:kFooKey];
bar = [aDecoder decodeObjectForKey:kBarKey];
someInt = [aDecoder decodeObjectForKey:kSomeIntKey];
someFloat = [aDecoder decodeObjectForKey:kAgeKey];
}
return self;
}
该方法使用
[super init] 初始化对象实例,如果初始化成功,则它通过解码NSCoder的实例中传递的值来设置其属性。
当为某个具有父类且遵循NSCoding的类实现NSCoding时,
initWithCoder:方法应稍有不同。
它不再对super调用init,
而是调用initWithCoder,像这样:(instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
foo = [aDecoder decodeObjectForKey:kFooKey];
bar = [aDecoder decodeObjectForKey:kBarKey];
someInt = [aDecoder decodeObjectForKey:kSomeIntKey];
someFloat = [aDecoder decodeObjectForKey:kAgeKey];
}
return self;
}
只要实现这两个方法,就可以对所有对象的属性进行编码和解码,然后便可以对对象进行归档,并且可以将其写入归档或者从归档中读取它们。