NSCoding
很多时候,我们需要将我们的处于内存里的对象保存到磁盘里,方便下次使用这个对象。其中,这个保存过程叫做归档-archive。相反,把磁盘里的数据变成对象,则称为解档-unarchive。
而unarchive中包含把二进制数据转化成对象的过程,称为序列化;相反,把一个对象变成磁盘里的文件这个归档过程中,对象转变成二进制数据这个过程,就就反序列化。
或者这样理解:序列化是把看似凌乱的二进制数据变成有序的结构体(内存里的对象其实就是以结构体的形式存在的),反序列化就是把有序的结构体对象变成看似凌乱的二进制数据。
NSCoding协议声明了一个可被归档与解档的类所必须实现的方法。遵循这个协议就必须实现里边的两个个方法:
// 归档
- (void)encodeWithCoder:(NSCoder *)encoder
// 解档
- (instancetype)initWithCoder:(NSCoder *)decoder
通常,它们是这么实现的:
// 归档
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.firstName forKey:ASCPersonFirstName];// object ->
[coder encodeObject:self.lastName forKey:ASCPersonLastName];
[coder encodeFloat:self.height forKey:ASCPersonHeight];// float -> 注意区别!
}
// 解档
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self) {
_firstName = [coder decodeObjectForKey:ASCPersonFirstName]; // -> object
_lastName = [coder decodeObjectForKey:ASCPersonLastName];
_height = [coder decodeFloatForKey:ASCPersonHeight]; // -> float 注意区别!
}
return self;
}
另外,需要归档 、解档的时候通常这么写:
// 1.归档
MyObject *object = [MyObject new];
NSString * documentDir= [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString * archivePath = [documentDir stringByAppendingPathComponent:@"objFile"];
[NSKeyedArchiver archiveRootObject:object toFile:archivePath];
// 2.解档
MyObject *object1 = [NSKeyedUnarchiver unarchiveObjectWithFile:archivePath];
NSCopying/NSMutableCopying
NSCopying
这个协议主要是用于实现自定义对象的拷贝,且是不可变的拷贝。里边也就只有一个必须实现的方法:
// 浅拷贝/指针拷贝
- (id)copyWithZone:(NSZone *)zone
你要想一个自定义的对象能得到合适的拷贝,那么你得遵循这个协议并实现这个方法,然后 自定义的类对象[aCustomInstance copy] 才可能正确工作。
ps:对象调用copy方法,其实就是简单的调用了copyWithZone:方法。
一般的实现可能是:
// 情况1-父类没有实现copyWithZone:
@interface MyBaseObject : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, assign) NSInteger value;
- (id)copyWithZone:(NSZone *)zone {
//MyObject *newObject = [MyObject new];//这种做法的问题就是:当被子类调用时,返回的对象会有问题。我们希望返回的是-目标对象。
MyObject *newObject = [[self class new]];// 创建一个目标类的对象,通过newObject指针完成对MyObject对象的拷贝工作。
if(newObject){
newObject.name = _name;
newObject.date = _date;
newObject.value = _value;
}
return newObject;
}
/*===========================================================================*/
// 情况2 - 父类实现了 copyWithZone:
@interface MySubObject : MyBaseObject
@property (nonatomic, copy)NSString *property1;
@property (nonatomic, copy)NSString *property2;
@end
- (id)copyWithZone:(NSZone *)zone {
MySubObject *newObject = [super copyWithZone:zone];
if (newObject){//完成本类中自定义属性(实例变量)的拷贝工作。
newObject.property1 = _property1;
newObject.property2 = _property2;
}
return newObject;
}
当MyObject类里又包含其它自定义的类,可变数组,不可变数组等情况时,则更为复杂,需要根据类设计初衷来考虑这个方法的实现。
NSMutableCopying
此协议仅声明了一个方法:mutableCopyWithZone: ,但是可变的拷贝常常是通过 mutableCopy 调起。这个mutableCopy 方法是在所有的 NSObject 类中定义,且只是简单的调用 mutableCopyWithZone: 而已。
如NSCopying协议一样,如果父类实现了NSMutableCopying协议,那么在实现子类的mutableCopyWithZone: 方法时,需先调用父类的 mutableCopyWithZone: 。
小结
感觉NSCopying协议平时在开发中使用的机会还是比较少(咳咳,其实我只是在文档、笔试题里或者技术博客里见到过一些介绍,或者常见的系统内置类型,如:NSString/NSMutableString、NSArray/NSMutableArray等)。所以具体的实战可能最好比较或者参考一下这些已有的类或者接口。