AutoCoding 是 NSObject 类别,为任何对象提供 NSCoding 的自动支持。这意味着您不必亲自实现 initWithCoder:
和 encodeWithCoder:
方法,您的应用程序中的所有模型类都可以在不需编写任何额外代码的情况下保存或从文件中加载。
当然,没有任何自动的系统能够读取您的想法,因此 AutoCoding 对您如何设计类有一定的限制;例如,您应该避免使用通过 NSValue 已经符合 NSCoding 的结构体。
使用 AutoCoding 绝对不是一刀切的决策。您可以在您项目的任何类上实现自己的 NSCoding 或 NSCopying 方法,并简单地覆盖自动生成的方法。
注意:"支持" 意味着该库已经与该版本进行了测试。"兼容" 意味着该库应该可以在该操作系统版本上运行(即它不依赖于不可用的 SDK 功能),但不再进行兼容性测试,可能需要调整或修复错误才能正确运行。
AutoCoding 兼容 ARC 和非 ARC 编译目标。
AutoCoding 完全线程安全。
要在您的项目中使用 AutoCoding 类别,只需将 AutoCoding.h 和 .m 文件拖动到您的项目中即可。
从2.0版本开始,AutoCoding自动支持NSSecureCoding协议,默认情况下,对所有对象调用+supportsSecureCoding
方法都返回YES。除此之外,假设你没有重写+supportsSecureCoding
以返回NO,当尝试解码一个类型与被分配属性不匹配的类时,AutoCoding将自动抛出异常。这使得恶意方难以构造一个NSCoded文件,当你的应用加载此文件时,不会执行你不希望执行的代码。
从2.1版本开始,NSCopying不再自动实现,因为它与Core Data NSManagedObjects存在一些兼容性问题。如果你想实现复制,可以通过以下方式轻松实现:遍历可编码属性的键,并逐个将这些属性复制到新对象实例中。
- (id)copyWithZone:(id)zone
{
id copy = [[[self class] alloc] init];
for (NSString *key in self.codableProperties)
{
[copy setValue:[self valueForKey:key] forKey:key];
}
return copy;
}
为了正确支持NSCopying,你还应该重写任何你要用于复制的对象的-hash
和-isEqual:
方法,以确保复制对象具有相同的哈希值,并且与原始对象相等。
要排除你的对象中某些属性被编码,可以采取以下任何一种方式
如果你想在对属性进行加载之前或之后进行类初始化,重写(setWithCoder:)方法,并在应用你自己的逻辑之前或之后调用超实现,如下所示
- (void)setWithCoder:(NSCoder *)coder
{
//pre-initialisation
[super setWithCoder:coder];
//post-initialisation
}
请注意,与先前版本不同,在使用initWithCoder:时,不调用init方法。
如果对象通过NSCoding加载后,你要执行某些清理、后处理或替换不同的对象,你可以使用NSObject类引用中定义的awakeAfterUsingCoder:方法。
通过重写setWithCoder:和/or encodeWithCoder:方法,可以添加额外的编码/解码逻辑。只要调用[super ...]实现,自动编码仍然会起作用。
如果你想在给定的属性类型中替换不同的类 - 例如,如果你更改了类名,但希望保留使用旧类名保存的文件兼容性,可以通过使用[NSKeyedUnArchiver setClass:forClassName:]方法为给定的名称替换不同的类。
如果你有不支持NSCoding的类型(例如,一个结构体)的属性,并且你想通过应用转换函数自己进行编码,通过更改ivar名称将属性标记为不可编码,并重写setWithCoder:和encodeWithCoder:方法(记得在调用超实现那些方法的同时自动加载和保存对象的其它属性)。如下所示:
@synthesize uncodableProperty = noencode_uncodableProperty; //non-KVC-compliant name
- (void)setWithCoder:(NSCoder *)coder
{
[super setWithCoder:coder];
self.uncodableProperty = DECODE_VALUE([coder decodeObjectForKey:@"uncodableProperty"]);
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[super encodeWithCoder:coder];
[coder encodeObject:ENCODE_VALUE(self.newProperty) forKey:@"uncodableProperty"];
}
如果你更改了属性的名称,但想检查旧的键名称的存在性以进行向后兼容性,重写setWithCoder:方法并添加检查旧属性,如下所示:
- (void)setWithCoder:(NSCoder *)coder
{
[super setWithCoder:coder];
self.newProperty = [coder objectForKey:@"oldProperty"] ?: self.newProperty;
}
如果你更改了属性的名称,但想使用旧的键名称进行加载和保存以进行向后兼容性,给新属性一个不符合KVC规范的ivar名称,并重写setWithCoder:/encodeWithCoder:方法以使用旧名称保存和加载属性(记得调用那些方法的超实现以自动加载和保存对象的其它属性)。如下所示:
@synthesize newProperty = noencode_newProperty; //non-KVC-compliant name
- (void)setWithCoder:(NSCoder *)coder
{
[super setWithCoder:coder];
self.newProperty = [coder objectForKey:@"oldProperty"];
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[super encodeWithCoder:coder];
[coder encodeObject:self.newProperty forKey:@"oldProperty"];
}
版本 2.2.2
版本 2.2.1
版本 2.2
版本 2.1
版本 2.0.3
版本 2.0.2
版本 2.0.1
版本 2.0
版本 1.3.1
[super copyWithZone:]
将不再正常工作。如果需要这样做,请重写 copy
方法并调用 [super copy]
代替版本 1.3
版本 1.2.1
版本 1.2
版本 1.1.2
instancetype
而不是 id,这使得在加载的实例上使用点语法属性访问器变得更简单。版本 1.1.1
版本 1.1
版本1.0