cocoa Shallow Copy与Deep Copy

  先做个关于Core Foundation对象复制简单的介绍:

  一般来讲,标准的复制,指的是简单的赋值操作的调用,也就是使用 = 操作符来赋值一个变量给另一个变量,比如说:

1 int a = 5;
2 int b;
3 
4 b = a;

那么b就获得了一份a的拷贝,b和a的内存地址是不同的,他们各占不同的内存区域。但是如果你这种方式企图复制一个Core Foundation对象,那么复制的仅仅是对象的引用,而对象本身并没有得到实际的复制。

用代码来说明一切吧:

首先是不可变对象的copy与mutableCopy:

1 //不可变对象的copy
2 NSString *str = [NSString stringWithFormat:@"123"];
3                 
4 NSString *cpstr = [str copy];//浅拷贝,str:2 ,cpstr:2
5        
6 NSLog(@"STR:%p recount = %ld",str,[str retainCount]);
7 NSLog(@"CPstr:%p recount = %ld",cpstr,[cpstr retainCount]);

2012-07-25 00:19:25.193 copy[11248:403] STR:0x1093145a0 recount = 2

2012-07-25 00:19:25.195 copy[11248:403] CPstr:0x1093145a0 recount = 2

注:str与cpstr指向同一个对象,copy后对象的引用计数增加为2

 

1 //不可变对象的mutableCopy
2 NSString *str = [NSString stringWithFormat:@"123"];
3         
4 NSMutableString *cpstr = [str mutableCopy];//深拷贝,str:1 ,cpstr:1
5         
6 NSLog(@"STR:%p recount = %ld",str,[str retainCount]);
7 NSLog(@"CPstr:%p recount = %ld",cpstr,[cpstr retainCount]);

2012-07-25 00:19:45.694 copy[11278:403] STR:0x7fe55ac145a0 recount = 1

2012-07-25 00:19:45.696 copy[11278:403] CPstr:0x7fe55ac14ad0 recount = 1

注:str与cpstr指向不同的对象,mutableCopy没有影响str的引用计数。

 

 

然后是可变对象的copy与mutablecopy

1 //可变对象的copy
2 NSMutableString *str = [NSMutableString stringWithFormat:@"123"]; 
3
4 NSString *cpstr = [str copy];//深拷贝,str:1 ,cpstr:1 5 6 NSLog(@"STR:%p recount = %ld",str,[str retainCount]); 7 NSLog(@"CPstr:%p recount = %ld",cpstr,[cpstr retainCount]);

2012-07-25 00:20:39.851 copy[11329:403] STR:0x7fe820c14a30 recount = 1

2012-07-25 00:20:39.853 copy[11329:403] CPstr:0x7fe820c14890 recount = 1

注:str与cpstr指向不同的对象,copy没有影响str引用计数。并且copy得到的对象是不可变的,所以不能改变cpstr。

1  //可变对象的mutableCopy
2 NSMutableString *str = [NSMutableString stringWithFormat:@"123"];
3         
4 NSMutableString *cpstr = [str mutableCopy];//深拷贝,str:1 ,cpstr:1
5         
6 NSLog(@"STR:%p recount = %ld",str,[str retainCount]);
7 NSLog(@"CPstr:%p recount = %ld",cpstr,[cpstr retainCount]);

2012-07-25 00:21:08.570 copy[11362:403] STR:0x101214a30 recount = 1

2012-07-25 00:21:08.572 copy[11362:403] CPstr:0x101214b20 recount = 1

注意:str与cpstr指向不同的对象。

总结一下就是:

1.不可变对象的copy是浅拷贝,就如retain性质一样,而mutableCopy则是深拷贝,新的内存拷贝。

2.可变对象的copy、mutableCopy都是深拷贝,内存的复制。需注意的是copy得到的对象是不可变的。

 

 


 

关于系统容器类的copy、mutableCopy:与上述一致。

比如:

 NSArray *array = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
        
 NSArray *cparr = [array copy];
        
 NSLog(@"array:%p recount = %ld",array,[array retainCount]);
 NSLog(@"cpArray:%p recount = %ld",cparr,[cparr retainCount]);

array:0x10c3147a0 recount = 2

cpArray:0x10c3147a0 recount = 2

cparr和cparr指向相同的对象(NSArray)。对象中的元素指向相通的对象(@"a",@"b",@"c");也就是说,把array对象想像成普通对象(例如NSString),一个道理。cparry只是另一份引用而已。画图说明再:

而mutable需要说明一下,先看结果

1 NSArray *array = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
2         
3 NSArray *cparr = [array mutableCopy];
4         
5 NSLog(@"array:%p recount = %ld object0:%p",array,[array retainCount],[array objectAtIndex:0]);
6 NSLog(@"cpArray:%p recount = %ld object1:%p",cparr,[cparr retainCount],[cparr objectAtIndex:0]);

array:0x7fbc234147a0 recount = 1 object0:0x10357e098

cpArray:0x7fbc234168e0 recount = 1 object1:0x10357e098

继续用图:

这是什么意思呢?cparray是array的可变副本,也就是说数组本身得到了深度拷贝,但是其指向的对象还是一份!理由就是上述打印出来的第一个元素的地址。用C来讲就是指针得到了赋值,两份地址几个,但是地址中保存的数据仍旧是1份。其实我感觉这已经是深拷贝了,因为NSArray里存储的本来就是引用(或者叫地址、指针),而这些东西已经得到了真实的复制了。

 

Array的深拷贝

两种方法:

1 initWithArray:copyItems: 使用 YES作为参数(这种方式得到的效果跟上面图示效果一致)

使用这种方法,NSArray里的每一个对象会收到copyWithZone消息,这些对象必须遵循NSCopying协议,要不就会导致运行时错误。其实这也是一种真正意义的深拷贝,为什么呢?因为copyWithZone产生的也是浅拷贝。这种拷贝只适合一级深度的拷贝。是不是晕乎了??各位

2.更真正意义的深拷贝!:NSCoding协议

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

 

参考:apple文档https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html

实验的代码:https://github.com/cokecoffe/ios-demo/tree/master/copy

上述是本人对与copy的理解,如有不对的地方,欢迎大家指正,我也是新手一枚! 

 

posted on 2012-07-25 00:23  cokecoffe  阅读(1345)  评论(3编辑  收藏  举报

导航