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

  • 相关阅读:
    leetcode5 Longest Palindromic Substring
    leetcode17 Letter Combinations of a Phone Number
    leetcode13 Roman to Integer
    leetcode14 Longest Common Prefix
    leetcode20 Valid Parentheses
    leetcode392 Is Subsequence
    leetcode121 Best Time to Buy and Sell Stock
    leetcode198 House Robber
    leetcode746 Min Cost Climbing Stairs
    tomcat下使用druid配置jnid数据源
  • 原文地址:https://www.cnblogs.com/cokecoffe/p/2607477.html
Copyright © 2011-2022 走看看