在ObjC中,什么是深浅拷贝?  深浅拷贝分别指深拷贝和浅拷贝,即 mutableCopy 和 copy 方法。  copy复制一个不可变对象,而 mutableCopy 复制一个 mutable 可变对象。

非容器类对象  如NSString,NSNumber等一类对象 
示例1:

  1. // 非容器类对象
  2. NSString *str = @"origin string";
  3. NSString *strCopy = [str copy];
  4. NSMutableString *mstrCopy = [str mutableCopy];
  5. [mstrCopy appendString:@"??"];
  6.  
  7. // NSLog(@"array1 = %p", array1);
  8. // NSLog(@"arrayCopy1 = %p", arrayCopy1);

查看内存可以发现,str和strCopy指向的是同一块内存区域,我们称之为弱引用(weak reference)。而mstrCopy是真正的复制,系统为其分配了新内存空间,保存从str复制过来的字符串值。从最后一行代码中修改这些值而不影 响str和strCopy中可证明。

示例2:

  1. NSMutableString *mstr = [NSMutableString stringWithString:@"origin"];
  2. NSString *strCopy = [mstr copy];
  3. NSMutableString *mstrCopy = [mstr copy];
  4. NSMutableString *mstrMCopy = [mstr mutableCopy];
  5. //[mstrCopy appendString:@"1111"]; //error
  6. [mstr appendString:@""];
  7. [mstrMCopy appendString:@""];

以上四个对象所分配的内存都是不一样的。而且对于mstrCopy,它所指向的其实是一个imutable对象,是不可改变的,所以会出错。这点要注意,好好理解。

小结: 
1.如果对一个不可变对象复制,copy是指针复制,即浅拷贝;而mutableCopy则是对象复制,即深拷贝。 
2.如果是对可变对象复制,都是深拷贝,但是copy复制返回的对象是不可变的。

容器类对象深浅复制 
比如NSArray,NSDictionary等。对于容器类本身,上面讨论的结论也适用的,下面探讨的是复制后容器内对象的变化。

示例3:

  1. /* copy返回不可变对象,mutablecopy返回可变对象 */
  2. NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
  3. NSArray *arrayCopy1 = [array1 copy];
  4. //arrayCopy1是和array同一个NSArray对象(指向相同的对象),包括array里面的元素也是指向相同的指针
  5. NSLog(@"array1 retain count: %d",[array1 retainCount]);    // 2
  6. NSLog(@"array1 retain count: %d",[arrayCopy1 retainCount]); // 2
  7.  
  8. NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
  9. //mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的还是同一个对象。mArrayCopy1还可以修改自己的对象
  10. [mArrayCopy1 addObject:@"de"];
  11. [mArrayCopy1 removeObjectAtIndex:];

array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,符合前面示例1讨论的结论。mArrayCopy1可以改变其内的元素:删除或添加。但容器内的元素内容都是浅拷贝。

示例4

  1. NSArray *mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
  2. NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
  3. NSArray *mArrayCopy2 = [mArray1 copy];
  4. NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
  5. // mArray1和mArrayCopy2指向同一对象,retain值+1。
  6.  
  7. NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy];
  8. NSLog(@"mArray1 retain count: %d",[mArray1 retainCount]);
  9. //mArrayCopy2和mArray1指向的是不一样的对象,但是其中的元素都是一样的对象——同一个指针
  10.  
  11. NSMutableString *testString = [mArray1 objectAtIndex:];
  12. //testString = @"1a1";//这样会改变testString的指针,其实是将@“1a1”临时对象赋给了testString
  13. [testString appendString:@" tail"];//这样以上三个数组的首元素都被改变了

由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。

示例5

  1. NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"] ,[NSString stringWithString:@"b"],@"c",nil];
  2. NSArray *deepCopyArray=[[NSArray alloc] initWithArray: array copyItems: YES];
  3. NSLog(@"array[2] = %@, deepCopyArray[2]=%@ ",[array objectAtIndex:], [deepCopyArray objectAtIndex:]); //输出值是一样的
  4. NSLog(@"array[2] %p", [array objectAtIndex:]);
  5. NSLog(@"deepCopyArray[2] %p", [deepCopyArray objectAtIndex:]);
  6. //最后两个打印的log内存地址值是一样的
  7.  
  8. NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array]];

trueDeepCopyArray 是完全意义上的深拷贝,而deepCopyArray则不是,对于 deepCopyArray 内的不可变元素其还是指针复制。

自己实现深拷贝的方法 NSDictionaryMutableDeepCopy.h

  1. #import <foundation /Foundation.h>
  2. @interface NSDictionary(MutableDeepCopy)
  3. - (NSMutableDictionary *)mutableDeepCopy;
  4. @end

NSDictionaryMutableDeepCopy.m

  1. #import "NSDictionaryMutableDeepCopy.h"
  2. @implementation NSDictionary(MutableDeepCopy)
  3. - (NSMutableDictionary *)mutableDeepCopy {
  4. NSMutableDictionary *ret = [[NSMutableDictionary alloc]
  5. initWithCapacity:[self count]];
  6. NSArray *keys = [self allKeys];
  7. for (id key in keys) {
  8. id oneValue = [self valueForKey:key];
  9. id oneCopy = nil;
  10. if ([oneValue respondsToSelector:@selector(mutableDeepCopy)]) {
  11. oneCopy = [oneValue mutableDeepCopy];
  12. }
  13. else if ([oneValue respondsToSelector:@selector(mutableCopy)]) {
  14. oneCopy = [oneValue mutableCopy];
  15. }
  16. if (oneCopy == nil) {
  17. oneCopy = [oneValue copy];
  18. }
  19. [ret setValue:oneCopy forKey:key];
  20. }
  21. return ret;
  22. }

使用类别方法来实现 
如果是我们定义的对象,那么我们自己要实现NSCopying,NSMutableCopying这样就能调用copy和mutablecopy了。举个例子

  1. @interface MyObj : NSObject<nscopying ,NSMutableCopying>
  2. {
  3. NSMutableString *name;
  4. NSString *imutableStr;
  5. int age;
  6. }
  7. @property (nonatomic, retain) NSMutableString *name;
  8. @property (nonatomic, retain) NSString *imutableStr;
  9. @property (nonatomic) int age;
  10.  
  11. @end
  12.  
  13. @implementation MyObj
  14. @synthesize name;
  15. @synthesize age;
  16. @synthesize imutableStr;
  17. - (id)init
  18. {
  19. if (self = [super init])
  20. {
  21. self.name = [[NSMutableString alloc]init];
  22. self.imutableStr = [[NSString alloc]init];
  23. age = -;
  24. }
  25. return self;
  26. }
  27.  
  28. - (void)dealloc
  29. {
  30. [name release];
  31. [imutableStr release];
  32. [super dealloc];
  33. }
  34. - (id)copyWithZone:(NSZone *)zone
  35. {
  36. MyObj *copy = [[[self class] allocWithZone:zone] init];
  37. copy->name = [name copy];
  38. copy->imutableStr = [imutableStr copy];
  39. // copy->name = [name copyWithZone:zone];;
  40. // copy->imutableStr = [name copyWithZone:zone];//
  41. copy->age = age;
  42. return copy;
  43. }
  44. - (id)mutableCopyWithZone:(NSZone *)zone
  45. {
  46. MyObj *copy = NSCopyObject(self, , zone);
  47. copy->name = [self.name mutableCopy];
  48. copy->age = age;
  49. return copy;
  50. }
  51. @end



ios学习路线—Objective-C(深浅拷贝)的更多相关文章

  1. ios 学习路线总结

    学习方法 面对有难度的功能,不要忙着拒绝,而是挑战一下,学习更多知识. 尽量独立解决问题,而不是在遇到问题的第一想法是找人. 多学习别人开源的第三方库,能够开源的库一定有值得学习的地方,多去看别的大神 ...

  2. iOS开发——iOS学习路线

    iOS学习路线 版权声明:欢迎转载,请贴上源地址:http://www.cnblogs.com/iCocos/(iOS梦工厂) 一:自学初步学习路线 二:高级完整学习路线 三:完整知识与能力体系 思维 ...

  3. python 学习笔记5(深浅拷贝与集合)

    拷贝 我们已经详细了解了变量赋值的过程.对于复杂的数据结构来说,赋值就等于完全共享了资源,一个值的改变会完全被另一个值共享. 然而有的时候,我们偏偏需要将一份数据的原始内容保留一份,再去处理数据,这个 ...

  4. iOS学习路线

    这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选区.这个学习路线必须发布到首页候选 ...

  5. 学习--->更新集合/内存/深浅拷贝

     一.计算机基础 1..软件(应用程序) 2.解释器/编译器 - 解释型语言:将代码每一行传递给计算机一行,常用编程语言python,PHP,Ruby. - 编译型语言:将代码完全执行完后会形成一个文 ...

  6. (2018干货系列十一)最新iOS学习路线整合

    怎么学iOS iOS是由苹果公司开发的移动操作系统,以xcode为主要开发工具,具有简单易用的界面.令人惊叹的功能,以及超强的稳定性,已经成为iPhone.iPad 和iPod touch 的强大基础 ...

  7. ios学习路线—Objective-C(Runtime消息机制)

    RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编译完成之后直接顺序执行,无任何 ...

  8. ios学习路线—Objective-C(新特性)

    1.方法顺序无关 Objective-C类由声明文件h和实现文件m组成,所有的public方法都在h文件中声明,private方法可以写在m文件中,但是在早期的编译环境中需要注意方法的顺序,例如下面的 ...

  9. ios学习路线—Objective-C(属性修饰符)

    readonly: 此标记说明属性是只读的,默认的标记是读写,如果你指定了只读,在@implementation中只需要一个读取器.或者如果你使用@synthesize关键字,也是有读取器方法被解析. ...

随机推荐

  1. python简单验证码

    安装图片处理模块pillow :   pip install pillow pillow官网:http://pillow.readthedocs.io/en/latest/ 在views.py添加视图 ...

  2. Android微信支付—注意事项

    坑点一:PayReq的参数 sign的生成 PayReq对象有个参数为packageValue 而sign生成时要用到packageValue,但是对应的Key是package,这里的key容易弄错 ...

  3. 从零开始——MySql01

    注:如有侵权,请速联系,会速度删除!(都是同学分享的内容) 安装详解: 链接:http://pan.baidu.com/s/1skMQVgx 密码:z0xh Navicat安装包: 链接:http:/ ...

  4. Spring MVC 常用Jar包

    spring:http://maven.springframework.org/release/org/springframework/spring/ jackson:http://repo1.mav ...

  5. 山寨Facebook的Shimmer效果

    山寨Facebook的Shimmer效果 说明 主要是用到了CAGradientLayer的特性来实现特效效果,因为时间有限,并没有进行封装,待后续改进. 效果 源码(源码没有进行封装,细节都没有处理 ...

  6. 详细讲解WaterRefreshLoadMoreView的使用

    详细讲解WaterRefreshLoadMoreView的使用 效果图: 加载控件的源码在如下网址中:上拉加载下拉刷新控件WaterRefreshLoadMoreView 使用的源码: // // V ...

  7. 转载:python的编码处理(一)

    以下内容转载自: http://in355hz.iteye.com/blog/1860787 最近业务中需要用 Python 写一些脚本.尽管脚本的交互只是命令行 + 日志输出,但是为了让界面友好些, ...

  8. Top 25 Most Frequently Asked Interview Core Java Interview Questions And Answers

    We are sharing 25 java interview questions , these questions are frequently asked by the recruiters. ...

  9. 申请Let’s Encrypt永久免费SSL证书过程教程及常见问题

    配置证书https://easy.zhetao.com/   虽然目前Let’s Encrypt免费SSL证书默认是90天有效期,但是我们也可以到期自动续约,不影响我们的尝试和使用,为了考虑到文章的真 ...

  10. Mosquitto安装调试实录

    1. 安装 以Centos 7.x为例,先安装依赖项(笔者使用阿里云资源,部分依赖项可能未列出): yum install gcc-c++ yum install openssl-devel yum ...