浅拷贝与深拷贝
程序中经常会遇到集合类的传值
坑: 数组操作时对于数组中的对象拷贝
###目的:
观察array1、mArrayCopy、mArrayCopy2 三者区别
1 2 3
| NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSArray *mArrayCopy = [[NSArray alloc] initWithArray:array1 copyItems:YES]; NSArray* mArrayCopy2 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array1]];
|
首先了解copy与retain的区别
OC对象引用计数器:屋里开灯规则
copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。
retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。
主角:copy、mutableCopy
注意:可变和不可变对象使用copy、mutableCopy的区别
遵守NSCopying 协议的类可以发送copy消息,
遵守NSMutableCopying 协议的类才可以发送mutableCopy消息。
默认的ios类并没有遵守这两个协议
自定义copy 必须遵守NSCopying,并且实现 copyWithZone: 方法
自定义mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法
实例
系统的非容器类对象
这里指的是NSString,NSNumber等等一类的对象。
示例1:
不可变string
1 2 3 4 5 6 7 8 9 10
| NSString *string = @"origionStr"; NSString *string2 = string; NSString *stringCopy = [string copy]; NSMutableString *stringMCopy = [string mutableCopy]; [stringMCopy appendString:@"!!!!"]; // log NSLog(@"string = %p %p %@ ",string,&string,string); NSLog(@"string2 = %p %p %@ ",string2,&string2,string2); NSLog(@"stringCopy = %p %p %@ ",stringCopy,&stringCopy,stringCopy); NSLog(@"stringMCopy = %p %p %@ ",stringMCopy,&stringMCopy,stringMCopy);
|
结果:
1 2 3 4
| string = 0x1064e7088 0x7fff597190a0 origionStr string2 = 0x1064e7088 0x7fff59719098 origionStr stringCopy = 0x1064e7088 0x7fff59719090 origionStr stringMCopy = 0x7fafebdbb4b0 0x7fff59719088 origionStr!!!!
|
示例2:
可变string
1 2 3 4 5 6 7 8 9 10
| NSMutableString *string = [NSMutableString stringWithString: @"origion"]; NSString *stringCopy = [string copy]; NSMutableString *mStringCopy = [string copy]; NSMutableString *stringMCopy = [string mutableCopy]; [string appendString:@" origion!"]; [stringMCopy appendString:@"!!"]; NSLog(@"string = %p %@",string,string); NSLog(@"stringCopy = %p %@",stringCopy,stringCopy); NSLog(@"stringMCopy = %p %@",mStringCopy,mStringCopy); NSLog(@"stringMCopy = %p %@",stringMCopy,stringMCopy);
|
结果:
1 2 3 4
| string = 0x7fafebdec820 origion origion! stringCopy = 0x7fafebdcb8c0 origion stringMCopy = 0x7fafebda4320 origion stringMCopy = 0x7fafebd32890 origion!!
|
对于系统的非容器类对象,我们可以认为,如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
系统的容器类对象
指NSArray,NSSet,NSDictionary等。对于容器类本身,上面讨论的结论也是适用的,需要探讨的是复制后容器内对象的变化。
示例1:
不可变数组
1 2 3 4 5 6 7 8 9 10
| //copy返回不可变对象,mutablecopy返回可变对象 NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil]; NSArray *arrayCopy1 = [array1 copy]; NSMutableArray *mArrayCopy1 = [array1 mutableCopy]; [mArrayCopy1 addObject:@"de"]; [mArrayCopy1 removeObjectAtIndex:0]; // log NSLog(@"array1 = %p %@ %p %@",array1,array1,array1[1],array1[1]); NSLog(@"arrayCopy1 = %p %@ %p %@",arrayCopy1,arrayCopy1,arrayCopy1[1],arrayCopy1[1]); NSLog(@"mArrayCopy1 = %p %@ %p %@",mArrayCopy1,mArrayCopy1,mArrayCopy1[0],mArrayCopy1[0]);
|
结果:
1 2 3
| array1 = 0x7fafebdeaed0 (a,b,c) 0x1064e7228 b arrayCopy1 = 0x7fafebdeaed0 (a,b,c) 0x1064e7228 b mArrayCopy1 = 0x7fafebdfc010 (b,c,de) 0x1064e7228 b
|
示例:
可变数组
1 2 3 4
| NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil]; NSMutableArray *mArrayCopy = [[NSMutableArray alloc] initWithArray:array1 copyItems:YES]; NSLog(@"array1 = %p %@ %p %@ %p %@",array1, array1, array1[0], array1[0], array1[1], array1[1]); NSLog(@"arrayCopy1 = %p %@ %p %@ %p %@",mArrayCopy,mArrayCopy, mArrayCopy[0], mArrayCopy[0], mArrayCopy[1], mArrayCopy[1]);
|
结果:
1 2
| array1 = 0x7fafebcb5ae0 (a,b,c) 0x10afe1208 a 0x10afe1228 b arrayCopy1 = 0x7fafebcb5b10 (a,b,c) 0x10afe1208 a 0x10afe1228 b
|
示例2:
1 2 3
| NSArray *array1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSMutableArray *mArrayCopy = [[NSMutableArray alloc] initWithArray:array1 copyItems:YES]; NSArray* mArrayCopy2 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array1]];
|
mArrayCopy2是完全意义上的深拷贝,而mArrayCopy则不是
对于mArrayCopy内的不可变元素其还是指针复制。或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制即已足够。