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,一经查实,立即删除!

相关文章

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文件 …

Arrays.sort与Arrays.parallelSort

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

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

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

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;。 让我们仔细…

使用Amazon Web Services(EC2)

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

盒子模型阴影设置,爱奇艺阴影配置

box-shadow的配置阴影 ul li:hover{ border-color: #dfdfdf; border-radius: 10px; -moz-box-shadow: 0 5px 5px rgba(0, 0, 0, 0.1), 0 0 10px 0 rgba(0, 0, 0, 0.2); -webkit-box-shadow: 0 5px 5px rgba(0, 0, 0, 0.1), 0 0 10px 0 rgba(0, 0, 0, 0.2); box-shadow: 0 5px 5…

第四周PSP

1.本周PSP 2.本周进度条 3.本周累计进度图 代码积累折线图 博文字数积累折线图 4.本周PSP饼状图 转载于:https://www.cnblogs.com/yuanyue-nenu/p/7648565.html

适用于JDeveloper 11gR2的Glassfish插件

众所周知&#xff0c; ADF Essentials是使用Java构建Web应用程序的绝佳框架&#xff0c;它可以自由开发和部署。 您可以在Glassfish&#xff08;3.1&#xff09;服务器上部署ADF Essentials应用程序。 但是&#xff0c;JDeveloper并不带有嵌入式Glassfish服务器&#xff0c;而是…

java 李刚 pdf_Java数据库技术详解(李刚) PDF_源雷技术空间

资源名称&#xff1a;Java数据库技术详解(李刚) PDF第一篇 数据库基础篇第1章 Java和数据库 21.1 Java概述 21.1.1 跨平台性 21.1.2 面向对象 21.1.3 安全性 31.1.4 简单性 31.1.5 健壮性和自动内存管理 31.2 Java的开发和运行环境 31.2.1 JDK的安装 31.2.2 配置JDK的环境变量 …

Java EE CDI处理程序方法示例

这是CDI Disposer方法的教程。 在CDI中&#xff0c;由于Producer方法生成的对象随后可以注入到应用程序中&#xff0c;因此使用Disposer方法&#xff0c;以便在其工作完成时将其删除。 Disposer方法始终与Producer方法匹配。 Disposer方法的使用示例是应用程序使用与数据库的连…

转 如何更改linux文件的拥有者及用户组(chown和chgrp)

本文整理自&#xff1a; http://blog.163.com/yanenshun126/blog/static/128388169201203011157308/http://ydlmlh.iteye.com/blog/1435157一、基本知识在Linux中&#xff0c;创建一个文件时&#xff0c;该文件的拥有者都是创建该文件的用户。该文件用户可以修改该文件的拥有者…

上下div高度动态自适应--另类处理方案

这段时间在工作中遇到一个看似较为棘手的问题。问题描述&#xff1a;查询报表页面分为上下两部分&#xff0c;上部分为条件输入区域&#xff0c;下部分为报表展示区域。客户要求做到默认满屏&#xff08;但要动态适应不同的窗体大小&#xff0c;也就是浏览器窗体用户会手动改变…

201571030316/201571030314 《小学四则运算练习软件需求说明》结对项目报告

小伙伴儿的博客地址链接&#xff1a;http://www.cnblogs.com/mjuan/p/8877738.html 我的学号&#xff1a;201571030316 小伴儿的学号&#xff1a;201571030314 一、调研过程&#xff1a; 1. 调查问卷&#xff1a;https://www.wjx.cn/jq/22680271.aspx利用问卷…

23种设计模式之一(单例模式)

单例模式&#xff1a;&#xff08;确保一个类最多只有一个实例&#xff0c;并提供一个全局访问点&#xff09; 存在的意义&#xff1a; 有些对象我们只需要一个&#xff0c;如&#xff1a;线程池、缓存、硬件设备等&#xff1b;如果使用多个实例就会造成冲突、不一致等&#xf…

mysql监控

1、查看mysql所有线程&#xff1a;show full processlist;SHOW PROCESSLIST显示哪些线程正在运行。如果您有SUPER权限&#xff0c;即root权限之类&#xff0c;您可以看到所有线程。否则&#xff0c;您只能看到您自己的线程&#xff08;也就是&#xff0c;与您正在使用的MySQL账…

vSphere ESXi主机配置iSCSI存储

vSphere ESXi主机配置iSCSI存储 vSphere ESXi主机一般连接的存储类型有光纤存储、iSCSI存储两类。本次案例为iSCSI存储连接ESXi主机的配置。 案例环境&#xff1a;ESXi主机通过以太网络来连接iSCSID存储&#xff0c;并获取到存储空间&#xff0c;拓扑如下&#xff1a; 首先完成…

linux上验证cudnn是否安装成功_deepin15.7中安装tensorflow+cuda9.0+cudnn7的步骤

这次deepin15.7大更新&#xff0c;特别是深度学习环境搭建屡屡失败&#xff0c;很是恼火。本次按照下面的步骤做成功了&#xff0c;以下是deepin15.7下安装tensorflowcuda9.0cudnn7的全部流程。硬件1.神舟战神z7-kp7s1&#xff0c;双显卡双硬盘2.独显是gtx1060 6G系统安装1.下载…

【ichart】简单的统计图表ichart.js的使用

1、首先下载&#xff0c;点击下载 2、只需要这一个js&#xff0c;粘贴赋值到自己项目中即可。 3、引入js <script type"text/javascript" src"../js/ichart.1.2.min.js"></script> <script type"text/javascript" src"..…