深拷贝和浅拷贝(copy & mutableCopy)

时间:2021-05-02 19:51:06

一、Copy

1、NSObject的对象方法,返回值=通过NSCopying协议中copyWithZone:返回的对象。

2、如果类实现NSCopying协议,copy很便利,否则会导致异常。

3、NSObject本身不支持NSCopying协议,子类想调用copy,必须支持该协议,且实现copyWithZone:方法。

4、子类实现copyWithZone:时,除了NSObject的子类,需先向上调用[super copyWithZone:zone],保证继承来的父类属性也能在copyWithZone:中初始化。

举例如下;

// Person继承自NSObject,Student继承自Person,均实现NSCopying协议

@implementation Person
- (id)copyWithZone:(NSZone *)zone
{
    Person *p = [[[self class] alloc] init]; // <== 注意这里。如果不这样写,子类通过[super copyWithZone:zone]创建的是父类对象,会引发一系列的问题 
    p.userId = self.userId;
    return p;
}
@end

@implementation Student
- (id)copyWithZone:(NSZone *)zone
{
    Student *s = [super copyWithZone:zone]; // 必须调用
    s.studentId = self.studentId;
    return s;
}
@end

 

二、拷贝

有两种类型的对象拷贝:浅拷贝和深拷贝。一般的拷贝是浅拷贝,浅拷贝创建新的collection却跟老collection共享对象。Collections包括数组、字典、集合等等。深拷贝就是拷贝了老collection且重新添加老collection内的对象,区别如下图:

深拷贝和浅拷贝(copy & mutableCopy)

1、浅拷贝

提供了许多浅拷贝collection的方式。创建浅拷贝时,老collection发送retain消息,拷贝指针成为新collection。例如以下方法就是浅拷贝:

NSArray *shallowCopyArray = [someArray copyWithZone:nil];
 
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];

不仅仅可以通过上面的方式,也通过copyWithZone:实现的copy,或者mutableCopyWithZone:方法,或者数组的initWithArray:copyItems:方法,均可实现浅拷贝。

通过copy一个非mutable对象,新的collection和旧的collection地址一致,只是retainCount+1,为浅拷贝。

通过mutableCopy,或者copy一个mutable对象,新collection的地址和旧collection的地址不一致,且为浅拷贝。

2、深拷贝

两种创建深拷贝的方式。

1)通过initWithArray:copyItems:方法且第二个参数传YES,这种创建深拷贝的方式是给collection中的每个对象都发送copyWithZone:消息。如果没有实现NSCopying协议,试图拷贝collection的对象,会导致运行时错误。如果也实现了NSCopying协议,且协议中的copyWithZone:方法是深拷贝,那就是真正意义的深拷贝。然而如果copyWithZone:方法是浅拷贝。这类拷贝只是第一层次的深拷贝,如@[@[@[]],@[]],只是深拷贝了最外面[]中的元素。如下举例说明:

NSArray *deepCopyArray=[[NSArray alloc] initWithArray:someArray copyItems:YES];

以上方式也可用于其它的collection。

2)如果需要真正的深拷贝,例如深拷贝数组,可以通过archive归档和unarchive解档 collection,使内容都实现NSCoding协议,举例如下:

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];

 

三、参考文档

苹果官方:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html