深拷贝和 浅拷贝的概念
首先在谈论iOS深拷贝和浅拷贝之前先给出对应概念
深拷贝 :浅拷贝并不拷贝对象本身,只是对指向对象的指针进行拷贝
浅拷贝 :直接拷贝对象到内存中一块区域,然后把新对象的指针指向这块内存
一个小小的注意事项
在iOS中并不是所有对象都支持Copy和MutableCopy,遵循NSCopying协议的类可以发送Copy协议,遵循NSMutableCopying协议的类可以发送MutableCopy消息。如果一个对象没有遵循这两个协议而发送Copy或者MutableCopy消息那么会发生异常。
同时如果要遵循NSCopying协议,那么必须实现copyWithZone方法。如果要遵循NSMutableCopying协议那么必须实现mutableCopyWithZone方法。
可变对象和不可变对象分别调用Copy和MutableCopy方法的区别
非集合类对象
分别调用 copy 和 mutableCopy 方法 如下
NSString *str = @"4065";
NSString *strCopy = [str copy];
NSMutableString *mustr = [str copy];
NSMutableString *muCopy = [str mutableCopy];
[mustr appendString:@"is hanhan"]; //会直接崩溃 (copy和mutableCopy的区别在于copy在复制对象的时候其实是返回了一个不可变对象,因此当调用方)
[muCopy appendString:@"is hanhan"];
NSLog(@"str = %@ strCopy = %@ mustr = %@ muCopy = %@",str,strCopy,mustr,muCopy);
NSLog(@"str地址%p strCopy地址%p mustr地址%p muCopy地址%p",str ,strCopy,mustr,muCopy);
输出结果
上面可以看出对系统非集合类不可变对象调用Copy方法其实只是把当前对象的指针指向了原对象的地址,而调用mutableCopy方法则是新分配了一块内存区域并把新对象的指针指向了这块区域。对于可变对象来说调用Copy和MutableCopy方法都会重新分配一块内存
集合类容器
NSArray *array = [NSArray arrayWithObjects:@"hanhan",@"lengleng",@"gangjing",@"is 4065 ",nil];
NSArray *arrayCopy = [array copy];
NSMutableArray *muarray = [array copy];
NSMutableArray *copyArray = [array mutableCopy];
NSLog(@"array地址%p arrayCopy地址%p muarray地址%p copyArray地址%p",array,arrayCopy,muarray,copyArray);
输出结果
NSMutableArray *muarray = [NSMutableArray arrayWithObjects:@"hanhan",@"lengleng",@"gangjing",@"is 4065 ",nil];
NSArray *array = [muarray copy];
NSArray *mutableCopy = [muarray mutableCopy];
NSMutableArray *muCopy = [muarray copy];
NSMutableArray *arrayCopy = [muarray mutableCopy];
NSLog(@"muarray地址%p array地址%p mutableCopy地址%p muCopy地址%p arrayCpy地址%p",muarray,array,mutableCopy,muCopy,arrayCopy);
由上面两个例子可知道
集合类对象的copy与mutableCopy:在集合类对象中,对 immutable 对象进行 copy,是指针复制, mutableCopy 是内容复制;对 mutable 对象进行 copy 和 mutableCopy 都是内容复制。但是:集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制。用代码简单表示如下:
[immutableObject copy] // 浅复制
[immutableObject mutableCopy] //单层深复制
[mutableObject copy] //单层深复制
[mutableObject mutableCopy] //单层深复制
那么如何进行完全深复制呢?
我们在这里提供两种做法
第一种
NSDictionary shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES];
如果你用这种方法深复制,集合里的每个对象都会收到 copyWithZone: 消息。如果集合里的对象遵循 NSCopying 协议,那么对象就会被深复制到新的集合。如果对象没有遵循 NSCopying 协议,而尝试用这种方法进行深复制,会在运行时出错。copyWithZone: 这种拷贝方式只能够提供一层内存拷贝(one-level-deep copy),而非真正的深复制。
第二个方法是将集合进行归档(archive),然后解档(unarchive),如:
NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];