深拷贝和浅拷贝(copy & mutableCopy)
一、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内的对象,区别如下图:
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]];
三、参考文档