IOS中的深拷贝和浅拷贝
标签:
什么是深拷贝?什么是浅拷贝?
为什么经常看到字符串属性要这样定义,那个copy是神马意思?
- @property(nonatomic,copy)NSString* name;
为什么下面的写法是错误的?
- @property(nonatomic,copy)NSMutableString* name;
copyWithZone方法又到底是干嘛用的?
接下来,我们将一起,一步一步的去揭晓问题的答案。
Copy到底是个啥?
其实我们真的没必要把copy想的太高深。它之所以叫copy,其终极目的已不言而喻,不管我们承认与否,它就是和Ctrl+c和Ctrl+v的作用一样。拷贝一个副本出来,使得两个对象直接互不影响,完全独立。
深拷贝浅拷贝
copy分为两种,一种是可变copy:MutableCopy。使用它copy出来的对象是可以对其内容进行改变的。另外一种是不可变copy:copy。使用它复制出来的对象,其内容是不可以改变的。
MutableCopy:可变拷贝,其拷贝过程就是在内存中重新开辟一块区域,将对象复制一份放到这个区域。新对象是可以改变的,而且新对象的改变对源对象是没有影响的。
copy:不可变copy,同样也是要开辟一段内存空间给新对象,但新对象是不可以改变的。(特殊情况:不可变-》不可变的拷贝,是不创建新内存空间的)
(注:这里的可变copy和不可变copy是相对Foundation框架的类而言的,如果我们自己定义的类实现copy,一般都是可变的)。
以上说的这些和深拷贝浅拷贝有什么关系呢?我举一个例子大家立刻就明白了。
假设我们要对一个不可变的对象进行不可变copy(原来的对象不可变,新对象也不可变)。那么大家觉的,我们还有必要给新对象新建一块内存么?反正大家都不可以对这个对象进行改变,那就统一使用着一个不就可以了么?那么,ios系统怎么处理这个问题呢?引用计数器加1啊。是的,这就是浅拷贝。而需要给新对象开闭内存空间的,就是深拷贝。
好,接下来我们通过一段代码说明上述问题:
- - (void)viewDidLoad {
- [super viewDidLoad];
- //创建一个可变的字符串
- NSMutableString* name = [NSMutableString stringWithFormat:@"好梦园的兔子"];
- NSLog(@"源字符串:%p-%@",name,name);
- //可变-》可变
- NSMutableString* name1 = [name mutableCopy];
- [name1 appendString:@"1"];
- NSLog(@"可变字符串:%p-%@",name1,name1);
- //可变-》不可变
- NSString* name2 = [name copy];
- NSLog(@"不可变字符串:%p-%@",name2,name2);
- NSLog(@"___________不可变到不可变______________");
- //不可变-》不可变
- NSString* weibo = @"好梦园的兔子";
- NSLog(@"源字符串:%p-%@",weibo,weibo);
- NSString* weibo1 = [weibo copy];
- NSLog(@"新字符串:%p-%@",weibo1,weibo1);
- }
大家观察运行结果中的对象地址:
- 2015-08-15 15:25:12.045 copy的那些事[1207:108085] 源字符串:0x7fede25a2f50-好梦园的兔子
- 2015-08-15 15:25:12.046 copy的那些事[1207:108085] 可变字符串:0x7fede25a1690-好梦园的兔子1
- 2015-08-15 15:25:12.046 copy的那些事[1207:108085] 不可变字符串:0x7fede25a1b10-好梦园的兔子
- 2015-08-15 15:25:12.046 copy的那些事[1207:108085] ___________不可变到不可变______________
- 2015-08-15 15:25:12.047 copy的那些事[1207:108085] 源字符串:0x10abe2188-好梦园的兔子
- 2015-08-15 15:25:12.047 copy的那些事[1207:108085] 新字符串:0x10abe2188-好梦园的兔子
Copy属性
- @property(nonatomic,copy)NSString* name;
我们大家在初学oc的时候,想必都听老师们说过这样一句话,创建属性的时候,遇到字符串括号里就写copy。但这究竟是为什么呢,我问老师,老师说他的老师就是这么说的。呵呵,开个玩笑。
我们先说明一点,这样做导致的结果就是,你给属性赋值的时候,会进行一次拷贝操作。至于目的嘛,接下来你会找到答案的。废话不多说,上代码:
- /*
- 新建一个Student类,里面有两个属性,nameCopy和nameStrong。
- 我们接下来就要看看这里的copy到底有什么用
- */
- @interface Student : NSObject
- @property(nonatomic,copy)NSString* nameCopy;
- @property(nonatomic,strong)NSString* nameStrong;
- @end
- - (void)viewDidLoad {
- [super viewDidLoad];
- //新建一个可变的字符串
- NSMutableString* name = [NSMutableString stringWithFormat:@"好梦园的兔子"];
- NSLog(@"源字符串:%p-%@",name,name);
- //创建Student对象
- Student * student1 = [[Student alloc]init];
- student1.nameCopy = name;//记住,此时会进行一次copy操作,因为(nonatomic,copy)
- student1.nameStrong = name;
- NSLog(@"nameCopy:%p-%@",student1.nameCopy,student1.nameCopy);
- NSLog(@"nameStrong:%p-%@",student1.nameStrong,student1.nameStrong);
- /*
- 通过上述代码,我们发现,(nonatomic,copy)修饰的属性,赋值时进行了copy操作,开辟了一块内存存放该对象属性
- (nonatomic,strong)赋值时,对象属性和源字符串共用了一块内存,只是对源字符串引用计数器+1。
- */
- NSLog(@"—————————————源字符串改变—————————————————————");
- //对源字符串进行改变 看看nameCopy和nameStrong哪个会受到影响
- [name setString:@"字符串改变了"];
- NSLog(@"nameCopy:%p-%@",student1.nameCopy,student1.nameCopy);
- NSLog(@"nameStrong:%p-%@",student1.nameStrong,student1.nameStrong);
- }
运行结果:
- 2015-08-15 16:09:07.698 copy的那些事[1504:130239] 源字符串:0x7f830a42fb00-好梦园的兔子
- 2015-08-15 16:09:07.699 copy的那些事[1504:130239] nameCopy:0x7f830a42c340-好梦园的兔子
- 2015-08-15 16:09:07.699 copy的那些事[1504:130239] nameStrong:0x7f830a42fb00-好梦园的兔子
- 2015-08-15 16:09:07.699 copy的那些事[1504:130239] ———————————————————源字符串改变———————————————————
- 2015-08-15 16:09:07.699 copy的那些事[1504:130239] nameCopy:0x7f830a42c340-好梦园的兔子
- 2015-08-15 16:09:07.700 copy的那些事[1504:130239] nameStrong:0x7f830a42fb00-字符串改变了
问题:
下面的写法有问题么?为什么?(下篇博客会为大家做解答)
- @property(nonatomic,copy)NSMutableString* name;
自定义类Copy
如果我们希望自己定义的类,也能使用copy方法,嗖嗖嗖就能复制一堆对象,那该如何操作呢。
假设我们直接使用copy
Student* student2 =[ student1 copy];
我们会发现,这时候程序会报错,说我们没有实现copyWithZone方法。这说明,我们是可以为自己的类定义copy方法的,只是要进行一些规范性的操作。
自定义类实现copy的步骤:
- #import <Foundation/Foundation.h>
- /*
- 创建一个Teacher类,并让该类实现copy方法
- */
- //1.遵守NSCopying协议
- @interface Teacher : NSObject<NSCopying>
- @property(nonatomic,copy)NSString* name;
- //2.实现copyWithZone方法;
- -(id)copyWithZone:(NSZone *)zone;
- @end
- #import "Teacher.h"
- @implementation Teacher
- //实现copyWithZone方法
- -(id)copyWithZone:(NSZone *)zone
- {
- Teacher* teacher = [[self.class alloc]init];
- teacher.name = self.name;
- return teacher;
- }
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- Teacher* teacher = [[Teacher alloc]init];
- teacher.name = @"好梦园的兔子";
- Teacher* teacher1 = [teacher copy];
- NSLog(@"teacher:%p-%@",teacher,teacher.name);
- NSLog(@"teacher1:%p-%@",teacher1,teacher1.name);
- }
运行结果:
- 2015-08-15 16:41:07.821 copy的那些事[1779:148657] teacher:0x7fd750d13ce0-好梦园的兔子
- 2015-08-15 16:41:07.822 copy的那些事[1779:148657] teacher1:0x7fd750d13cf0-好梦园的兔子
上述内容,是将我们自己定义的类实现了copy方法。那么这里有个问题,我可不可以让我自己定义的类实现mutableCopy呢?有没有NSMutableCopying协议呢?
还有,上述代码中,teacher.name 和teacher1.name 的地址其实是一样的。为什么?
最后一问答案比较简单,我就替大家回答了(copyWithZone方法中:tescher.name = self.name)
其他两问,按照实现copy的方法进行尝试,同样会很快得到答案的。
(完)
IOS中的深拷贝和浅拷贝的更多相关文章
- 浅谈Java中的深拷贝和浅拷贝(转载)
浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...
- C语言中的深拷贝和浅拷贝
//C语言中的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #inc ...
- 浅谈Java中的深拷贝和浅拷贝
转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...
- 内功心法 -- Java中的深拷贝和浅拷贝
写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------这篇博客主要来谈谈" ...
- **Python中的深拷贝和浅拷贝详解
Python中的深拷贝和浅拷贝详解 这篇文章主要介绍了Python中的深拷贝和浅拷贝详解,本文讲解了变量-对象-引用.可变对象-不可变对象.拷贝等内容. 要说清楚Python中的深浅拷贝,需要 ...
- javascript中的深拷贝与浅拷贝
javascript中的深拷贝与浅拷贝 基础概念 在了解深拷贝与浅拷贝的时候需要先了解一些基础知识 核心知识点之 堆与栈 栈(stack)为自动分配的内存空间,它由系统自动释放: 堆(heap)则是动 ...
- JavaScript中的深拷贝和浅拷贝!【有错误】还未修改!请逛其他园子!
JavaScript中的深拷贝和浅拷贝! 浅拷贝 1.浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用.{也就是拷贝的是地址!简而言之就是在新的对象中修改深层次的值也会影响原来的对象!} // 2.深 ...
- 001 说说Python中的深拷贝和浅拷贝
在Python编程中忽略深拷贝和浅拷贝可能会造成未知的风险. 比如我们打算保存一份原始对象的副本作为上一状态的记录,此后修改原始对象数据时,若是副本对象的数据也发生改变,那么这就是一个严重的错误. 注 ...
- IOS开发之深拷贝与浅拷贝(mutableCopy与Copy)详解
copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1.Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象 ...
随机推荐
- 深入requests库params|data|json参数
深入requests库params|data|json参数 一.params params:字典或者字节序列,作为参数增加到URL中.不仅访问URL,还可以向服务器携带参数. 简单来讲也就是说对于原来 ...
- javaWeb核心技术第十一篇之Listener
监听器:所谓的监听器是指对整个WEB环境的监听,当被监视的对象发生改变时,立即调用相应的方法进行处理. 监听术语: 事件源:被监听的对象. 监听器对象:监听事件源的对象 注册或绑定:1和2结合的过程 ...
- Andorid Studio 新建模拟器无法联网问题
1.查看自己本机的dns cmd -> ipconfing /all 2.修改模拟器的dns 跟PC本机一致. 开启模拟器 -> cmd -> adb root (需要root ...
- OSI参考模型总结
OSI(Open System Interconnect),即开放式系统互联. 一般都叫OSI参考模型,是ISO(国际标准化组织)组织在1985年研究的网络互连模型.下面我们将一层一层的看OSI协议. ...
- linux学习(四)复制(cp)移动(mv)删除(rm)查找(find)文件、文件夹操作、软硬链接的区别
目录 复制文件 mv命令 rm命令 touch 命令 file命令 find命令 grep命令 mkdir命令 rmdir命令 @(复制移动删除查找文件.软硬链接的区别) 复制文件 cp命令用于复制文 ...
- 如何获取数据泵dm和dw进程的 Strace (Doc ID 1411563.1)
How To Get A Strace Of The Data Pump dm And dw Process(es) (Doc ID 1411563.1) APPLIES TO: Oracle Dat ...
- centos图形化桌面安装过程
连接 1.安装xwindow yum -y groupinstall "X Window System" \\安装 X Window System 环境 2.安装gnome des ...
- 在 VS 中查看所有线程
查看当前所有线程 在程序中打断点,然后启动调试(注意:线程窗口需要启动调试才可以看得到)点击 Debug > Windows > Threads 线程窗口如下:
- 算法设计与分析 1.1 Joyvan的矩阵
★题目描述 Joyvan有一个大小为n * m的矩阵,现在他要对矩阵进行q次操作,操作分为如下三种: 0 x y:交换矩阵的x.y两行. 1 x y:交换矩阵的x.y两列. 2 x y:求当前矩阵第x ...
- fis3打包中的一些注意事项
1.在html文件中,如果在标签的style属性内添加路径,fis不会识别改路径并打包,如 2.fis主要针对静态文件进行打包.对其他文件打包会出现一些问题. 比如jsp页面.下面的例子script. ...