浅拷贝:只创建一个新的指针,指向原指针指向的内存。
深拷贝:创建一个新的指针,并开辟新的内存空间,内容拷贝自原指针指向的内存,并指向它。
假设我们要对一个不可变的对象进行不可变copy(原来的对象不可变,新对象也不可变)。就没必要给新对象新建一块内存,反正大家都不可以对这个对象进行改变,那都使用一个就可以。所以iOS系统规定浅拷贝引用计数器加1就行(多了一个指针指向)。而需要给新对象开闭内存空间的,就是深拷贝。
copy得到的类型一定是不可变的;mutableCopy得到的类型一定是可变的
使用mutable,都是深拷贝(不管是拷贝类型还是拷贝方法);但是copy也有深拷贝;
以下分类验证:
一、对于不可变对象
copy 浅拷贝(指针复制)
mutableCopy 深拷贝(对象复制 指针+内存)返回对象可变(产生新的可变对象)
image.png
image.png
二、对于可变对象
可变对象的不可变拷贝和可变拷贝皆为深拷贝,但是不可变拷贝返回的对象是不可变的。
1550760159859.jpg
image.png
总结:对于可变对象和不可变对象的可变拷贝和不可变拷贝,只有不可变对象的不可变拷贝是浅拷贝,其余三者皆为深拷贝。
三、容器对象(NSArray,NSMutableArray, NSDictionary,NSMutableDictionary, NSSet集合)遵循非容器对象的拷贝原则:
1551104144917.jpg
1551104259064.jpg
1551104344765.jpg
1551104469796.jpg
四、对象序列化,实现真正意义的拷贝(数组内的对象也实现深拷贝):
1551106042482.jpg
1551106093788.jpg
五、自定义对象拷贝需要实现NSCopying和NSMutableCopying协议。
六、深浅拷贝的几点应用
① 对于可变字符串,不可以使用copy关键字修饰。若用copy修饰这个可变字符串属性,当给可变字符串属性赋值时,setter方法会触发深拷贝,导致结果是可变字符串属性不再可变,因为可变字符串的copy返回不可变对象。
② string用copy还是用strong修饰?
最好用copy修饰,对于不可变对象,最好用copy, 而不是用strong, 其原因是一样的。
因为NString,NSArray,NSDictionary都有自己对应的子类:NSMutableString,NSMutableArray,NSMutableDictionary,而父类指针可以指向子类对象,使用copy修饰可以让本对象不受外界(子对象)影响,无论外界传入的是一个可变对象还是一个不可变对象,都能保证自身持有的是一个不可变副本。
使用strong修饰时,如果这个属性指向一个可变对象,修改可变对象时,这个属性值也会被修改。因为在赋值时,直接将属性的指针指向了可变对象。
如果不将一个可变对象赋值给不可变对象,自然不会出现上述情况,但是谨慎为好。另外,当然在将可变对象赋值给不可变对象时,先对可变对象进行copy操作,也可以避免上述操作,但是在编码中,可能会有遗忘,所以避免出现Bug, 还是用copy为好。
image.png
1551189487334.jpg
image.png
③ 界面传值,涉及到可变数组传给可变数组时,要先用mutableCopy然后再传值。而对于将一个可变数组传给一个不可变数组,不可变数组最好用copy修饰,或者对不可变对象进行copy操作。
1551191716314.jpg
1551191784282.jpg
转自: https://blog.csdn.net/donnydn/article/details/79381053
https://www.jianshu.com/p/1e1a6f9c26f8
注:部分内容参考
网友评论