最近在简书看到了一篇关于iOS深浅拷贝的博客,下面做一下学习总结:

非集合类对象的copy和mutableCopy

非集合类对象指NSString、NSNumber、NSMutableString等对象。对immutable(不可变对象)进行copy操作,就是简单的指针拷贝,进行mutableCopy操作时,是进行内容复制。对于mutable(可变对象)无论进行copy还是mutableCopy都是内容拷贝。

// 非集合类对象的copy和mutablecopy
// 1.不可变对象
NSString *str = @"hello";
NSString *str_copy = str.copy;
NSMutableString *str_mutecopy = str.mutableCopy;
[str_mutecopy appendString:@" world"]; NSLog(@"%@---%p----%@",str,str,[str class]);
NSLog(@"%@---%p----%@",str_copy,str_copy,[str_copy class]);
NSLog(@"%@---%p----%@",str_mutecopy,str_mutecopy,[str_mutecopy class]);
NSLog(@"\n"); // 输出
// 2018-05-19 22:26:17.847234+0800 深浅拷贝练习[5861:566828] hello---0x100002060----__NSCFConstantString
// 2018-05-19 22:26:17.847418+0800 深浅拷贝练习[5861:566828] hello---0x100002060----__NSCFConstantString
// 2018-05-19 22:26:17.847475+0800 深浅拷贝练习[5861:566828] hello world---0x10053bab0----__NSCFString //2.可变对象
NSMutableString *str_mute = [NSMutableString stringWithString:@"hello"];
NSString *str_mute_copy = str_mute.copy;
NSMutableString *str_mute_mutecopy = str_mute.mutableCopy;
[str_mute appendString:@" world"];
[str_mute_mutecopy appendString:@" Objective-C"]; NSLog(@"%@---%p----%@",str_mute,str_mute,[str_mute class]);
NSLog(@"%@---%p----%@",str_mute_copy,str_mute_copy,[str_mute_copy class]);
NSLog(@"%@---%p----%@",str_mute_mutecopy,str_mute_mutecopy,[str_mute_mutecopy class]); // 输出
// 2018-05-19 22:26:17.847544+0800 深浅拷贝练习[5861:566828] hello world---0x10053bc30----__NSCFString
// 2018-05-19 22:26:17.847601+0800 深浅拷贝练习[5861:566828] hello---0x6f6c6c656855----NSTaggedPointerString
// 2018-05-19 22:26:17.847619+0800 深浅拷贝练习[5861:566828] hello Objective-C---0x1005471d0----__NSCFString

集合类对象的copy和mutableCopy

集合类对象是指NSArray、NSDictionary等对象,对immutable对象进行copy,是指针拷贝,mutableCopy是进行内容拷贝。对mutable对象进行copy和mutableCopy时都是内容拷贝。但是集合对象的内容拷贝仅限于对象本身,对象元素仍然是指针拷贝。

//集合类对象的copy和mutablecopy
//1.不可变对象
NSArray *arr = @[@"",@"",@""];
NSArray *arr_copy = arr.copy;
NSMutableArray *arr_mutecopy = arr.mutableCopy;
[arr_mutecopy addObject:@""]; NSLog(@"%@----%p----%@",arr,arr,[arr class]);
NSLog(@"%@----%p----%@",arr_copy,arr_copy,[arr_copy class]);
NSLog(@"%@----%p----%@",arr_mutecopy,arr_mutecopy,[arr_mutecopy class]);
NSLog(@"\n"); // 输出
// 2018-05-19 22:34:39.850322+0800 深浅拷贝练习[5927:578661] (
// 1,
// 2,
// 3
// )----0x10070ae50----__NSArrayI
// 2018-05-19 22:34:39.850423+0800 深浅拷贝练习[5927:578661] (
// 1,
// 2,
// 3
// )----0x10070ae50----__NSArrayI
// 2018-05-19 22:34:39.850488+0800 深浅拷贝练习[5927:578661] (
// 1,
// 2,
// 3,
// 4
// )----0x10070b390----__NSArrayM //2.可变对象
NSMutableArray *arr_mute = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil];
NSArray *arr_mute_copy = arr_mute.copy;
NSMutableArray *arr_mute_mutecopy = arr_mute.mutableCopy;
[arr_mute addObject:@"4"];
[arr_mute_mutecopy addObject:@"5"]; NSLog(@"%@----%p----%@",arr_mute,arr_mute,[arr_mute class]);
NSLog(@"%@----%p----%@",arr_mute_copy,arr_mute_copy,[arr_mute_copy class]);
NSLog(@"%@----%p----%@",arr_mute_mutecopy,arr_mute_mutecopy,[arr_mute_mutecopy class]); // 输出
// 2018-05-19 22:34:39.850556+0800 深浅拷贝练习[5927:578661] (
//                                                     1,
//                                                     2,
//                                                     3,
//                                                     4
//                                                     )----0x1031061e0----__NSArrayM
// 2018-05-19 22:34:39.850571+0800 深浅拷贝练习[5927:578661] (
//                                                     1,
//                                                     2,
//                                                     3
//                                                     )----0x1031030a0----__NSArrayI
// 2018-05-19 22:34:39.850601+0800 深浅拷贝练习[5927:578661] (
//                                                     1,
//                                                     2,
//                                                     3,
//                                                     5
//                                                     )----0x103105910----__NSArray

注意:集合类深拷贝和非集合类的深拷贝还是不太一样的,当我们对集合类进行mutableCopy操作时,虽然内存地址改变了,但是数组元素内存地址并没有发生改变,这是一个特例,也就是并不是真正意义上的完全深拷贝,也就是单层深拷贝。

深拷贝(单层深拷贝)和完全拷贝

深拷贝就是把原来对象的内容直接克隆一份到新对象里,但是这里有一个坑就是,他只会复制一层,不会复制更深层次的对象,例如:

NSArray *arr = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"one"],@"two",@"three",@"four", nil];
NSMutableString *str = arr[];
[str appendString:@"- add some data"];
NSArray *arr_copy = arr.copy;
NSMutableArray *arr_mutecopy = arr.mutableCopy; NSLog(@"%@----%p----%@----%p",arr,arr,[arr class],arr[]);
NSLog(@"%@----%p----%@----%p",arr_copy,arr_copy,[arr_copy class],arr_copy[]);
NSLog(@"%@----%p----%@----%p",arr_mutecopy,arr_mutecopy,[arr_mutecopy class],arr_mutecopy[]); // 输出
// 2018-05-19 22:57:09.819322+0800 深浅拷贝练习[6068:602956] (
// "one- add some data",
// two,
// three,
// four
// )----0x100504fb0----__NSArrayI----0x10042aaa0
// 2018-05-19 22:57:09.819514+0800 深浅拷贝练习[6068:602956] (
// "one- add some data",
// two,
// three,
// four
// )----0x100504fb0----__NSArrayI----0x10042aaa0
// 2018-05-19 22:57:09.819569+0800 深浅拷贝练习[6068:602956] (
// "one- add some data",
// two,
// three,
// four
// )----0x100506a20----__NSArrayM----0x10042aaa0

由此可知,arr_copy和arr_mutecopy对arr进行了内容拷贝,但是arr的可变字符串却没有进行内容拷贝,而是进行了单纯的浅拷贝(指针拷贝),那么arr、arr_copy和arr_mutecopy元素中第一个元素字符串是共享的,由此可以看出深拷贝并不是真正意义的完全拷贝,只是单层深拷贝。

解决办法:

归档和接档

NSArray *arr = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"one"],@"two",@"three",@"four", nil];

//归档和接档的方法解决
NSMutableArray *arr_arc = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:arr]]; NSMutableString *str = arr[];
[str appendString:@"- add some data"];
NSArray *arr_copy = arr.copy;
NSMutableArray *arr_mutecopy = arr.mutableCopy; NSLog(@"%@----%p----%@----%p",arr,arr,[arr class],arr[]);
NSLog(@"%@----%p----%@----%p",arr_copy,arr_copy,[arr_copy class],arr_copy[]);
NSLog(@"%@----%p----%@----%p",arr_mutecopy,arr_mutecopy,[arr_mutecopy class],arr_mutecopy[]);
NSLog(@"%@----%p----%@----%p",arr_arc,arr_arc,[arr_arc class],arr_arc[]); // 输出
// 2018-05-19 22:57:09.819322+0800 深浅拷贝练习[6068:602956] (
// "one- add some data",
// two,
// three,
// four
// )----0x100504fb0----__NSArrayI----0x10042aaa0
// 2018-05-19 22:57:09.819514+0800 深浅拷贝练习[6068:602956] (
// "one- add some data",
// two,
// three,
// four
// )----0x100504fb0----__NSArrayI----0x10042aaa0
// 2018-05-19 22:57:09.819569+0800 深浅拷贝练习[6068:602956] (
// "one- add some data",
// two,
// three,
// four
// )----0x100506a20----__NSArrayM----0x10042aaa0
// 2018-05-20 20:54:26.698263+0800 深浅拷贝练习[6506:682670] (
// one,
// two,
// three,
// four
// )----0x100576610----__NSArrayI----0x100575e20

你真的了解iOS的深浅拷贝吗?的更多相关文章

  1. IOS开发之iOS深浅拷贝

    这里主要侧重于集合类的深浅拷贝,主要事因为工作的时候遇到这个问题. 有不足的地方欢迎指正 首先我们需要有这样的一个前提: [array addObject:obj]; 这样obj的引用计数会增加1,如 ...

  2. ios学习路线—Objective-C(深浅拷贝)

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

  3. @proprety数组字典字符串用copy和strong区别(深浅拷贝)

    ////  @proprety数组字典字符串用copy和strong区别(深浅拷贝).h//  IOS笔记//// /* _proprety________copy_strong_________h ...

  4. python基础(7)--深浅拷贝、函数

    1.深浅拷贝 在Python中将一个变量的值传递给另外一个变量通常有三种:赋值.浅拷贝.深拷贝 Python数据类型可氛围基本数据类型包括整型.字符串.布尔及None等,还有一种由基本数据类型作为最基 ...

  5. python day- 7 进本数据类型的先关知识点 set集合 深浅拷贝

    一.基本数据类型相关知识 1.str.    join()函数 关于字符串 a = "我爱北京" b = a.join("真的")            将&q ...

  6. 天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

    Python中的深浅拷贝 在讲深浅拷贝之前,我们先重温一下 is 和==的区别. 在判断对象是否相等比较的时候我们可以用is 和 == is:比较两个对象的引用是否相同,即 它们的id 是否一样 == ...

  7. Python 从零学起(纯基础) 笔记 之 深浅拷贝

    深浅拷贝 1. import  copy#浅拷贝copy.copy()#深拷贝copy.deepcopy()#赋值 = 2.   对于数字和字符串而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个 ...

  8. python——赋值与深浅拷贝

    初学编程的小伙伴都会对于深浅拷贝的用法有些疑问,今天我们就结合python变量存储的特性从内存的角度来谈一谈赋值和深浅拷贝~~~ 预备知识一——python的变量及其存储 在详细的了解python中赋 ...

  9. Python中的深浅拷贝

    1.什么是深浅拷贝? python中一切皆对象,python中的数字.字符串.元组等,如果存放在了内存中,这部分内存里面的内容是不会改变的,但是也有情况,内存中存放了可变对象,比如说列表和字典,他们的 ...

随机推荐

  1. 浙大PAT CCCC L3-015 球队“食物链” ( 搜索 && 剪枝 )

    题目链接 题意 : 有 n 个球队,给出主客场胜负图,找出一个序列 1.2.3..... 使得 1 战胜过 2 .2 战胜过 3.3 战胜过 4..... n 战胜过 1 ( 这个序列是 1~n 的其 ...

  2. FLASH位宽为8、16、32时,CPU与外设之间地址线的连接方法

    转 http://blog.csdn.net/linweig/article/details/5556819 flash连接CPU时,根据不同的数据宽度,比如16位的NOR FLASH (A0-A19 ...

  3. windows及linux下 golang开发环境配置

    windows环境: 1.系统以及软件包版本: OS: windows 8.1  64位  x64处理器 GO:安装包:go1.7.3.windows-amd64.mis IDE:压缩包:liteid ...

  4. RabbitMQ消费端自定义监听(九)

    场景: 我们一般在代码中编写while循环,进行consumer.nextDelivery方法进行获取下一条消息,然后进行消费处理. 实际环境: 我们使用自定义的Consumer更加的方便,解耦性更强 ...

  5. Zookeeper w3cschool教程

    1.简介 ZooKeeper是一种分布式协调服务,用于管理大型主机.在分布式环境中协调和管理服务是一个复杂的过程.ZooKeeper通过其简单的架构和API解决了这个问题. ZooKeeper允许开发 ...

  6. .bash_profile vs .bashrc

    w http://www.joshstaiger.org/archives/2005/07/bash_profile_vs.html

  7. 剑指 Offer——数组中的逆序对

    1. 题目 2. 解答 借助于归并排序的分治思想,在每次合并的时候统计逆序对.因为要合并的两个数组都是有序的,如果左半部分数组当前值大于右半部分数组当前值,那么左半部分数组当前值右边的数就都大于右半部 ...

  8. 阶段1 语言基础+高级_1-3-Java语言高级_07-网络编程_第4节 模拟BS服务器案例_2_模拟BS服务器代码实现

    这三行代码是固定的在输出之前 浏览器再次访问这个页面. 图片没有显示出来 复制刚才的代码一份出来重命名 加个while循环.把代码都放进去. 然后在while里面开启一个线程.把读取的代码都放在线程里 ...

  9. JMeter Gui – TestElement约定(转自约会言行的博客,链接:http://blog.csdn.net/yue530tomtom/article/details/77649872?locationNum=4&fps=1)

    在编写任何JMeter组件时,必须注意某些特定的约定——如果JMeter环境中正确地运行JMeter组件,那么它将会运行.本部分描述了组件的GUI部分必须满足的约定. JMeter中的GUI代码严格地 ...

  10. js中parseInt()与parseFloat(),Number(),Boolean(),String()转换

    js将字符串转数值的方法主要有三种 转换函数.强制类型转换.利用js变量弱类型转换. 1. 转换函数: js提供了parseInt()和parseFloat()两个转换函数.前者把值转换成整数,后者把 ...