zoukankan      html  css  js  c++  java
  • 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的理解,如有不对的地方,欢迎大家指正,我也是新手一枚! 

  • 相关阅读:
    九度oj 题目1051:数字阶梯求和
    九度oj 题目1472:求两个多项式的和
    九度oj 题目1173:查找
    九度oj 题目1447:最短路
    九度oj 题目1104:整除问题
    [Luogu] 维护序列
    [Luogu] 计算系数
    [Luogu] 聪明的质监员
    [Luogu] Mayan游戏
    [Luogu] 选择客栈
  • 原文地址:https://www.cnblogs.com/cokecoffe/p/2607477.html
Copyright © 2011-2022 走看看