iOS 图文并茂的带你了解深拷贝与浅拷贝

一、概念与总结

     1、浅拷贝

     浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间,当内存销毁的时候,指向这片内存的几个指针需要重新定义才可以使用,要不然会成为野指针。

      浅拷贝就是拷贝指向原来对象的指针,使原对象的引用计数+1,可以理解为创建了一个指向原对象的新指针而已,并没有创建一个全新的对象。

      2、深拷贝

      深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。

     深拷贝就是拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新的对象,创建后和原对象没有任何关系。

   

    3、总结:

    深拷贝就是内容拷贝,浅拷贝就是指针拷贝。本质区别在于:

  • 是否开启新的内存地址
  • 是否影响内存地址的引用计数

 

 二、示例分析

      在iOS中深拷贝与浅拷贝要更加的复杂,涉及到容器与非容器、可变与不可变对象的copy与mutableCopy。下面用示例逐一分析:

      1、非集合对象的copy与mutableCopy

        1.1 不可变对象NSString 

复制代码
- (void) noMutableNSStringTest
{NSString *str1 = @"test001";NSMutableString *str2 = [str1 copy];//copy返回的是不可变对象,str2不能被修改,因此会发生崩溃//[str2 appendString:@"test"];NSMutableString *str3 = [str1 mutableCopy];[str3 appendString:@"modify"];NSLog(@"str1:%p - %@ \r\n",str1,str1);NSLog(@"str2:%p - %@ \r\n",str2,str2);NSLog(@"str3:%p - %@ \r\n",str3,str3);
}
复制代码

          打印结果:

 

2017-07-20 18:02:10.642 beck.wang[1306:169414] str1:0x106abdbd0 - test001 
2017-07-20 18:02:10.643 beck.wang[1306:169414] str2:0x106abdbd0 - test001 
2017-07-20 18:02:10.643 beck.wang[1306:169414] str3:0x608000260940 - test001modify 

         分析:str1、str2地址相同并且与str3地址不同,NSString的copy是浅拷贝,且copy返回的对象是不可变对象;mutableCopy是深拷贝。

     

      1.2 可变对象NSMutableString

复制代码
- (void) mutableNSStringTest
{NSMutableString *mstr1 = [NSMutableString stringWithString:@"test002"];NSMutableString *mstr2 = [mstr1 copy];//copy返回的是不可变对象,mstr2不能被修改,因此会发生崩溃//[str2 appendString:@"test"];NSMutableString *mstr3 = [mstr1 mutableCopy];[mstr3 appendString:@"modify"];NSLog(@"mstr1:%p - %@ \r\n",mstr1,mstr1);NSLog(@"mstr2:%p - %@ \r\n",mstr2,mstr2);NSLog(@"mstr3:%p - %@ \r\n",mstr3,mstr3);
}
复制代码

        打印结果:

2017-07-20 18:14:35.789 beck.wang[1433:180881] mstr1:0x610000075e40 - test002 
2017-07-20 18:14:35.790 beck.wang[1433:180881] mstr2:0xa323030747365747 - test002 
2017-07-20 18:14:35.790 beck.wang[1433:180881] mstr3:0x610000074480 - test002modify 

        分析:mstr1、mstr2、mstr3 地址都不同,NSMutableString对象copy与mutableCopy都是深拷贝,且copy返回的对象是不可变对象。

 

    2、集合对象的copy与mutableCopy

       2.1 不可变对象NSArray

复制代码
- (void) mutableNSArrayTest
{NSArray *arry1 = [[NSArray alloc] initWithObjects:@"value1", @"value2",nil];NSArray *arry2 = [arry1 copy];NSArray *arry3 = [arry1 mutableCopy];NSLog(@"arry1:%p - %@ \r\n",arry1,arry1);NSLog(@"arry2:%p - %@ \r\n",arry2,arry2);NSLog(@"arry3:%p - %@ \r\n",arry3,arry3);
}
复制代码

       打印结果:

复制代码
2017-07-20 18:33:53.707 beck.wang[1502:194476] arry1:0x60800003b480 - (value1,value2
) 
2017-07-20 18:33:53.708 beck.wang[1502:194476] arry2:0x60800003b480 - (value1,value2
) 
2017-07-20 18:33:53.708 beck.wang[1502:194476] arry3:0x60800004cd20 - (value1,value2
) 
复制代码

      分析:arry1、arry2 地址一样,arr3 地址不一样,NSArray的copy是浅拷贝,且copy返回的对象是不可变对象;mutableCopy是深拷贝。

      

      2.2 可变对象NSMutableArray

复制代码
- (void) NSMutableArrayTest
{NSMutableArray *marry1 = [[NSMutableArray alloc] initWithObjects:@"value1", @"value2",nil];NSMutableArray *marry2 = [marry1 copy];//copy返回的是不可变对象,marry2不能被修改,因此会崩溃//[marry2 addObject:@"value3"];NSMutableArray *marry3 = [marry1 mutableCopy];NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);
}
复制代码

        打印结果:

复制代码
2017-07-20 18:55:43.243 beck.wang[1577:204641] marry1:0x600000048d60 - (value1,value2
) 
2017-07-20 18:55:43.244 beck.wang[1577:204641] marry2:0x600000026000 - (value1,value2
) 
2017-07-20 18:55:43.244 beck.wang[1577:204641] marry3:0x6000000494b0 - (value1,value2
) 
复制代码

       分析:marry1、marry2、marr3 地址都不一样,NSMutableArray对象copy与mutableCopy都是深拷贝,且copy返回的对象是不可变对象。

 

       特别注意的是:对于集合类的可变对象来说,深拷贝并非严格意义上的深复制,只能算是单层深复制,即虽然新开辟了内存地址,但是存放在内存上的值(也就是数组里的元素仍然之乡员数组元素值,并没有另外复制一份),这就叫做单层深复制。

       举例说明:

复制代码
- (void)singleNSMutableArrayTest
{NSMutableArray *marry1 = [[NSMutableArray alloc] init];NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];[marry1 addObject:mstr1];[marry1 addObject:mstr2];NSMutableArray *marry2 = [marry1 copy];NSMutableArray *marry3 = [marry1 mutableCopy];NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry2[0],marry2[1]);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry3[0],marry3[1]);NSLog(@"\r\n------------------修改原值后------------------------\r\n");[mstr1 appendFormat:@"aaa"];NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);NSLog(@"marry2:%p - %@ \r\n",marry2,marry2);NSLog(@"marry3:%p - %@ \r\n",marry3,marry3);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry2[0],marry2[1]);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry3[0],marry3[1]);
}
复制代码

        打印结果:

复制代码
2017-07-20 19:48:24.539 beck.wang[1750:230132] marry1:0x60800004ae00 - (value1,value2
) 
2017-07-20 19:48:24.539 beck.wang[1750:230132] marry2:0x608000023f00 - (value1,value2
) 
2017-07-20 19:48:24.539 beck.wang[1750:230132] marry3:0x60800004abc0 - (value1,value2
) 
2017-07-20 19:48:24.540 beck.wang[1750:230132] 数组元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.540 beck.wang[1750:230132] 数组元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.540 beck.wang[1750:230132] 数组元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.540 beck.wang[1750:230132] 
------------------修改原值后------------------------
2017-07-20 19:48:24.540 beck.wang[1750:230132] marry1:0x60800004ae00 - (value1aaa,value2
) 
2017-07-20 19:48:24.540 beck.wang[1750:230132] marry2:0x608000023f00 - (value1aaa,value2
) 
2017-07-20 19:48:24.540 beck.wang[1750:230132] marry3:0x60800004abc0 - (value1aaa,value2
) 
2017-07-20 19:48:24.541 beck.wang[1750:230132] 数组元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.541 beck.wang[1750:230132] 数组元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
2017-07-20 19:48:24.541 beck.wang[1750:230132] 数组元素地址:value1:0x60800006df40 - value2:0x60800006cb40 
复制代码

      分析:在修改原值之前,marry1、marry2、marr3 地址都不一样,很明显copy和mutableCopy都是深拷贝,但是从修改原值后的打印结果来看,这里的深拷贝只是单层深拷贝:新开辟了内存地址,但是数组中的值还是指向原数组的,这样才能在修改原值后,marry2 marr3中的值都修改了。另外,从打印的数组元素地址可以很明显的看出来,修改前后marry1、marry、marr3的数组元素地址都是一模一样的,更加佐证了这一点。

 

      2.3 思维扩展:集合对象的完全深拷贝

            2.2中提到了集合类的对象来说,深拷贝只是单层深拷贝,那有没有办法实现每一层都深拷贝呢?回答是肯定的,目前我们可以这么做:

          (1)归档解档大法

复制代码
- (void) deplyFullCopy
{NSMutableArray *marry1 = [[NSMutableArray alloc] init];NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];[marry1 addObject:mstr1];[marry1 addObject:mstr2];NSData *data = [NSKeyedArchiver archivedDataWithRootObject:marry1];NSArray *marray2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:nil];NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);
}
复制代码

          打印结果:

复制代码
2017-07-20 20:04:38.726 beck.wang[1833:242158] marry1:0x600000048a00 - (value1,value2
) 
2017-07-20 20:04:38.726 beck.wang[1833:242158] marry2:0x600000049780 - (value1,value2
) 
2017-07-20 20:04:38.726 beck.wang[1833:242158] 数组元素地址:value1:0x600000066300 - value2:0x600000067000 
2017-07-20 20:04:38.726 beck.wang[1833:242158] 数组元素地址:value1:0x600000066740 - value2:0x600000066f40 
复制代码

        分析:我们可以看到,开辟了新的内存地址的同时,数组元素的指针地址也不同了,实现了完全的深拷贝。

      (2)- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;

复制代码
- (void) deplyFullCopy2
{NSMutableArray *marry1 = [[NSMutableArray alloc] init];NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"value1"];NSMutableString *mstr2 = [[NSMutableString alloc]initWithString:@"value2"];[marry1 addObject:mstr1];[marry1 addObject:mstr2];NSArray *marray2 = [[NSArray alloc] initWithArray:marry1 copyItems:YES];NSLog(@"marry1:%p - %@ \r\n",marry1,marry1);NSLog(@"marry2:%p - %@ \r\n",marray2,marray2);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marry1[0],marry1[1]);NSLog(@"数组元素地址:value1:%p - value2:%p \r\n",marray2[0],marray2[1]);
}
复制代码

        打印结果:

复制代码
2017-07-20 20:08:04.201 beck.wang[1868:246161] marry1:0x610000050320 - (value1,value2
) 
2017-07-20 20:08:04.202 beck.wang[1868:246161] marry2:0x6100002214c0 - (value1,value2
) 
2017-07-20 20:08:04.202 beck.wang[1868:246161] 数组元素地址:value1:0x610000265600 - value2:0x610000266400 
2017-07-20 20:08:04.202 beck.wang[1868:246161] 数组元素地址:value1:0xa003165756c61766 - value2:0xa003265756c61766 
复制代码

      分析:同上。

 

三、准则

      No1:可变对象的copy和mutableCopy方法都是深拷贝(区别完全深拷贝与单层深拷贝) 。

    No2:不可变对象的copy方法是浅拷贝,mutableCopy方法是深拷贝。

    No3:copy方法返回的对象都是不可变对象。

 

      万语千言汇成一张图

 

 

 更多:http://www.cnblogs.com/beckwang0912/p/7212075.html

转载于:https://www.cnblogs.com/tlios/p/7645574.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369037.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Byteman和JUnit进行故障注入

我们的应用程序独立存在的时间已经很久了。 如今&#xff0c;应用程序是一种非常复杂的野兽&#xff0c;它们使用无数的API和协议相互通信&#xff0c;将数据存储在传统或NoSQL数据库中&#xff0c;通过网络发送消息和事件……例如&#xff0c;如果考虑到数据库&#xff0c;您会…

Ambari Views的自定义

下载ambari源码&#xff0c; ambari-views/examples/ 下面有很多例子&#xff0c;直接编译是不会成功的&#xff0c; 因为每一个例子项目都需要一个依赖 <dependency><groupId>org.apache.ambari</groupId><artifactId>ambari-views</artifactId>…

angular使用sass的scss语法

一、现象 为了简写样式 二、解决 1、安装sass ,利用npm 安装(npm工具如果没有&#xff0c;请先自行安装好) &#xff08;1&#xff09;、npm install node-sass --save-dev &#xff08;2&#xff09;、npm install sass-loader --save-dev 2、修改.angular-cli.json文件 …

linux 查看java cpu_Linux查看CPU和内存使用情况

在系统维护的过程中&#xff0c;随时可能有需要查看 CPU 使用率&#xff0c;并根据相应信息分析系统状况的需要。在 CentOS 中&#xff0c;可以通过 top 命令来查看 CPU 使用状况。运行 top 命令后&#xff0c;CPU 使用状态会以全屏的方式显示&#xff0c;并且会处在对话的模式…

TCP浅谈为什么3次握手

《计算机网络》中的例子是这样的&#xff0c;“已失效的连接请求报文段”的产生在这样一种情况&#xff1a;客户发出的第一个连接请求报文段并没有丢失&#xff0c;而是在某个网络结点长时间的滞留了&#xff0c;以致延误到连接释放以后的某个时间才到达服务。 本来这是一个早已…

Arrays.sort与Arrays.parallelSort

我们都使用Arrays.sort对对象和原始数组进行排序。 该API在下面使用合并排序或Tim排序对内容进行排序&#xff0c;如下所示&#xff1a; public static void sort(Object[] a) {if (LegacyMergeSort.userRequested)legacyMergeSort(a);elseComparableTimSort.sort(a); }即使合…

了解ASP.NET MVC的基本架构

MVC&#xff0c;Model – View – Controller 的简写 Model 封装业务逻辑相关的数据及对数据的处理方法 View 向用户提供交互界面 Controller 负责控制Model和View 首先建立一个模板 在这里发现了一个问题&#xff08;好像vs12没有模板&#xff0c;建不出来&#xff09; 其…

Google Chrome 浏览器JS无法更新解决办法

JS无法更新原因&#xff1a; 浏览器为了加载快&#xff0c;默认是按照自定规则更新缓存&#xff0c;非实时更新。 我们在开发的时候&#xff0c;JS变动很快&#xff0c;需要即时让浏览器加载最新文件&#xff0c;也就是禁用浏览器缓存 &#xff08;1&#xff09;使用F12进入…

HDU3415 Max Sum of Max-K-sub-sequence

题意given a circle sequence A[1],A[2],A[3]......A[n]. Circle sequence means the left neighbour of A[1] is A[n] , and the right neighbour of A[n] is A[1]. Now your job is to calculate the max sum of a Max-K-sub-sequence. Max-K-sub-sequence means a continuou…

Spring:自动接线或不自动接线

从使用Spring 2.5开始&#xff0c;我从基于XML的应用程序上下文切换到了注释。 尽管我发现那些非常有用且节省大量时间的人&#xff0c;但我始终觉得在灵活性方面我失去了一些东西。 特别是Autowired批注-或标准Inject-在我看来就像新的“新”&#xff0c;增加了类之间的耦合&a…

刷题总结——Cut the Sequence(POJ 3017 dp+单调队列+set)

题目&#xff1a; Description Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subsequence of the original sequence. Every part must satisfy that the sum of the integers in the …

java crud事件回调_java回调机制 - 神是到着念的个人空间 - OSCHINA - 中文开源技术交流社区...

软件模块之间总是存在着一定的接口&#xff0c;从调用方式上&#xff0c;可以把他们分为三类&#xff1a;同步调用、回调和异步调用。同步调用是一种阻塞式调用&#xff0c;调用方要等待对方执行完毕才返回&#xff0c;它是一种单向调用&#xff1b;回调是一种双向调用模式&…

CSS盒子的浮动

在标准流中&#xff0c;一个块级元素在水平方向会自动伸展&#xff0c;直到包含它的元素的边界&#xff1b;而在竖直方向和兄弟元素依次排列&#xff0c;不能并排。使用“浮动”方式后&#xff0c;块级元素的表现就会有所不同。 CSS中有一个float属性&#xff0c;默认为no…

servlet中url-pattern之/与/*的区别

转载于:https://www.cnblogs.com/hwgok/p/8835350.html

很少使用“ ControlFlowException”

控制流是命令式编程的“遗留物”&#xff0c;它已泄漏到其他各种编程范例中&#xff0c;包括Java的面向对象范例 。 除了有用的和无处不在的分支和循环结构外&#xff0c;还包括原语&#xff08;例如GOTO&#xff09;和非局部变量&#xff08;例如异常&#xff09;。 让我们仔细…

java的if里有多个if_代码里写很多if会影响效率吗?

看你怎么写 if.嵌入很多层if的代码叫做“箭头代码”&#xff0c;是一个anti-pattern。 这种代码会增加程序的循环复杂度 (Cyclomatic complexity)具体可以看这里&#xff1a;Flattening Arrow Code这里&#xff1a;总的来说&#xff0c;程序里用if-else是有开销的。每次conditi…

python基础总结(6)

一、模块。 一个模块就是一个python文件&#xff0c;.py文件。 需要注意的是&#xff1a;自己创建模块时要注意命名&#xff0c;不能和Python自带的模块名称冲突。例如&#xff0c;系统自带了sys模块&#xff0c;自己的模块就不可命名为sys.py&#xff0c;否则将无法导入系统自…

[10.10模拟] water

题意&#xff1a; 有一块矩形土地被划分成 n*m 个正方形小块。这些小块高低不平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中。一场大雨后,由于地势高不同,许多地方都积存了不少降水。给定每个小块的高度,求每个…

使用Amazon Web Services(EC2)

正如我上周参加技术动手AWS培训之前所发布的。 这些天的课程当然是我以前使用过的标准EC2和S3服务。 除此之外&#xff0c;我们还使用了RDS &#xff0c; Elastic Load Balancing &#xff0c; SNS和VPC &#xff0c; Elastic Beanstalk并讨论了许多术语和业务案例。 在本文中&…

java整型和浮点型_Java基本的程序结构设计 整形和浮点型

整形&#xff1a;int 4字节short 2字节long 8字节byte 1字节int的大小差不多是20亿。整形计算如果两个int进行加减乘除数学运算的时候&#xff0c;最终的结果仍然是int&#xff0c;有可能出现了溢出&#xff0c;那么结果就不是我们想要的了。如下&#xff1a;System.out.printl…