copy & mutableCopy

2021-07-22  本文已影响0人  小李不木

浅拷贝和深拷贝的区别?

区别

深拷贝和浅拷贝

浅拷贝:相当于对指向对象的指针进行复制,产生一个新的指向这个对象的指针,两个指针指向同一个地址,没有发生新的内存分配。使原对象的引用计数+1,这个对象销毁后两个指针都应该置空。

深拷贝:深拷贝是对一个对象进行拷贝,相当于对对象进行复制,产生一个新的对象,那么就有两个指针分别指向两个对象(两片内容相同的内存空间)。当一个对象改变或者被销毁后另一个对象不受影响。不会增加被拷贝对象的引用计数,产生了新内存分配。


NSMutableArray用copy修饰会出现什么问题?

给Mutable 被声明为copy修饰的属性赋值, 当调用可变方法的增,删等操作时 会导致程序崩溃。 具体如下:

1. 如果是NSMutableArray对象,  copy 结果是不可变的,  就是NSArray

2. 如果赋值过来的是 NSArray 对象,  copy 结果仍是不可变的, 仍是 NSArray。 

所以不论赋值过来的是什么对象, 只要对 进行 copy 操作, 返回的对象都是不可变的。

原来属性声明的是NSMutable 类型 , 之后调用了 add 或者 remove 方法,然而 copy 后的结果是不可变对象,  所以一旦调用这些方法就会程序崩溃(crash)

NSString,NSNumber这些不能包含其他对象的叫做非容器类。

NSArray 和 NSDictionary 可以容纳其他对象的叫做容器类对象。

对于容器类的对象,深拷贝只能算是单层深复制拷贝后仅仅产生了两个内存地址不同的容器,它们的使用的是同一份元素,在修改原值后,被copy的数组里的值也都被修改了。由于数组或字典中对象数目或大小可能非常大,所以对对象的复制可能引起大量开销,因此这里单层深复制引用可以节省开销。

小结:

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

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

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

5:容器类是否可以深拷贝,首先要看最小元素,若最小元素为不可变类型,容器类的任何拷贝操作都是浅拷贝。

容器类的完全深拷贝是开辟了新的内存地址的同时,数组元素的指针地址也不同了,才是完全的深拷贝。


1、对于copy来说,如果源对象是不可变的,那么是浅拷贝,没有必要深拷贝;如果源对象可变,为了安全性,深拷贝,为了防止因原对象改变而造成拷贝对象改变。

编译器在编译时对 不可变对象进行 copy 时采取优化策略:即将不可变对象的地址直接赋值给拷贝对象,因为不可变对象无法进行修改,也就不存在拷贝后原值改变的情况,所以为了效率,即不再重新开辟空间,编译器对不可变对象采取了浅拷贝的方式。

因此我们在设置property的copy属性时,如果希望对象跟着源对象的值变化,那么就是用strong;

1. 容器类的深拷贝 都是单层深拷贝,即只是容器对象指向不同的内存空间,内部的元素则指向同一个内存地址 ,容器内的对象是浅拷贝(指针拷贝)

2. 数组完全深拷贝需要执行initWithArray:copyItems:方法,数组内元素为可变类型时,可以连元素一起拷贝,属于深拷贝(元素非容器)

NSArray*deepCopy = [[NSArray alloc] initWithArray:array copyItems:YES];

实现深拷贝需要遵守NSCoying协议,实现- (id)copyWithZone:(NSZone *)zone 方法。当一个property属性使用copy修饰符的时候,在进行赋值操作的时候实际上就是调用这个方法。

父类实现深拷贝之后,子类只要重写copyWithZone方法,在方法内部调用父类的copyWithZone方法,之后实现自己的属性的处理

父类没有实现深拷贝,子类除了需要对自己的属性进行处理,还要对父类的属性进行处理。

容器类的完全深拷贝可以通过归档解档大法来实现,代码如下  marry1 与 marray2可以实现完全深拷贝

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:marry1];

NSArray *marray2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:nil];

copy与retain的区别:

copy是创建一个新对象(要区分对象是容器类还是非容器类),retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关。copy减少对象对上下文的依赖。

 retain属性表示两个对象地址相同(指针拷贝,浅拷贝),内容当然相同,这个对象的retain+1,retain声明后的对象会更改引用计数,每次被引用,引用计数都会+1,释放后就会-1。只有当引用计数为0时,系统自动调用dealloc析构函数回收内存。

参考:

iOS关于Copy和mutableCopy方法的浅析_CoderL-CSDN博客

iOS 关于容器类的浅、深拷贝探究 - 简书

上一篇 下一篇

猜你喜欢

热点阅读