关于深拷贝和浅拷贝的理解

620 阅读4分钟

1,概念总结:

1.1,浅拷贝就是拷贝指向原来对象的指针,使原对象的引用计数+1,可以理解为创建了一个指向原对象的新指针而已,并没有额外分配内存地址,也不会创建一个全新的对象。

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

总结:浅拷贝拷贝的是指针,浅拷贝引用计数加1;深拷贝拷贝的是内存,深拷贝创建新的地址新的对象。

2,容器、非容器,可变、不可变对象的copy和mutableCopy分析

2.1,非容器对象-以NSString、NSMutableString举例,首先定义了NSString和NSMutableString,然后对创建的字符串对象进行copy和mutableCopy。得到了有规律并且奇奇怪怪的结果

如上图所看到的进行总结:

**1,对不可变对象执行copy方法,内存地址并没有发生改变,进行的是浅拷贝操作;
** 2,对不可变对象执行mutableCopy方法,内存地址发生改变,进行的是深拷贝操作; 3,对可变对象无论执行copy或者mutableCopy,内存地址都发生了变化,均进行的是深拷贝操作; 4,对直接常量赋值创建的字符串,那么字符串的对象存储的常量区,类型是NSCFConstantString ,同一个字符串常量创建出来的字符串对象的地址是一样的。

2.2,容器对象-以NSArray、NSMutableArray举例,分别创建NSArray、NSMutableArray数组,填入不可变字符串item0,和可变字符串item1,观察打印结果。

如上图进行总结:

**1,对不可变容器执行copy方法,内存地址没有发生变化,进行的是浅拷贝操作;
****2,对不可变容器执行mutableCopy方法,内存地址发生变化,进行的是深拷贝操作;
****3,对可变容器无论执行copy或mutableCopy方法,内存都会发生变化,均进行的是深拷贝操作;
****4,执行copy方法返回的数组是__NAArrayI类型,执行mutableCopy方法返回的数组是__NSArrayM类型,原因在于:空数组类型为__NSArray0,只有一个对象的数组类型为__NSSingleObjectArrayI,有对象的数组类型为__NSArrayI,可变数组类型为__NSArrayM;
****5,无论是可变容器还是不可变容器,无论执行的是copy或者mutableCopy,item0和item1都没有发生变化,进行的都是浅拷贝。
**6,所以mutableCopy返回的数组是可变数组,而copy返回的数组是不可变数组

3,关于容器单层拷贝和多层拷贝

3.1,对于容器类型的对象来说,深拷贝并非严格意义上的“深复制”,虽然开辟了新的内存地址,但是新开辟出来的数组内存的元素还是原始数组里的元素地址。这个叫做“单层深拷贝”。

从图上的打印可以看到,mArr1执行copy和mutableCopy之后,生成的mArr2、mArr3地址都不相同,但是mArr1[1]、mArr2[1]、mArr3[1]的地址是相同的,而且更改了item1的值后,打印的时候mArr1、mArr2、mArr3里的item1都发生了变化,也就证明数组的地址虽然不同但是数组元素的地址是相同的,修改元素item1的的时候,修改的是同一块内存地址里的数据。

3.2,实现集合对象的完全深拷贝(完全深复制)

第一种方法:归档接档实现完全深拷贝

从打印台里可以看到mArr4的地址和mArry1不同,mArr4[1]的地址和mArr1[1]的地址也不同,同时再36行更改了item1的值,但是并没有影响到mArr4[1]的item1,可以看出归档解档的过程进行了完全深拷贝。

第二种方法:利用数组初始化方法,告诉数组需要copyItems,拷贝元素

从打印台里可以看到mArr5的地址和mArry1不同,mArr5[1]的地址和mArr1[1]的地址也不同,同时再39行更改了item1的值,但是并没有影响到mArr5[1]的item1,可以看出这种初始化数组的方法也能进行完全深拷贝。