何为深拷贝, 何为浅拷贝?
深拷贝 : 拷贝出来的对象与源对象地址不一致! 这意味着我修改拷贝对象的值对源对象的值没有任何影响.
浅拷贝 : 拷贝出来的对象与源对象地址一致! 这意味着我修改拷贝对象的值会直接影响到源对象.
对于NSString对象, 确实深拷贝就是深拷贝, 浅拷贝就是浅拷贝, 没有任何异议.
但是对于NSArray, NSDictionary, NSSet这些容器类的对象呢? 当然浅拷贝依然是指针拷贝, 那深拷贝意味着连同容器及其容器内的对象一并拷贝吗? 还是只拷贝容器对象, 对容器内的对象则只是简单引用呢? 这里有两种情况, 我姑且把它称为不完全深拷贝与完全深拷贝
不完全深拷贝
不完全深拷贝就是只拷贝容器对象(拷贝一个壳), 而对于容器内的对象则只保存一份引用.
所以我们知道, 就算我们修改copyArray不会影响到源array, 但是我通过copyArray修改数组内的object, 对应地源array内的object也会随之修改, 大家可以自行测试
![](https://img.haomeiwen.com/i2782369/d8b6b8aa20231135.png)
完全深拷贝
完全深拷贝就是连同容器内的对象在内, 完完全全拷贝一份出来
通过图片可以很清楚地知道, 这种情况下无论是修改copyArray还是通过copyArray修改数组内的object, 对源array都不会造成半点影响.
![](https://img.haomeiwen.com/i2782369/79b0b8fbaec15375.png)
ps : 默认状态下深拷贝指的是不完全深拷贝, 如要实现完全深拷贝, 则要重写copyWithZone: 方法, 自行实现完全深拷贝的需求. 大体思路如下, 在copyWithZone: 里对象赋值上不直接赋值而是通过copy方法即可实现, 这里不作具体讨论.既然有朋友问到, 那就贴上示例代码吧
// Person.m
- (id)copyWithZone:(NSZone *)zone
{
Person *cpyPerson = [[Person allocWithZone:zone] init];
cpyPerson.name = self.name;
cpyPerson.age = self.age;
return cpyPerson;
}
// NSArray
- (id)copy
{
NSArray *cpyArray = [[NSArray alloc] initWithArray:self copyItems:YES];
return cpyArray;
}
// main.m
Person *p1 = [[Person alloc] init];
Person *p2 = [[Person alloc] init];
NSArray *array = @[p1, p2];
NSArray *cpyArray = [array copy];
NSLog(@"%@ - %@", array, cpyArray);
// 输出结果
(
"<Person: 0x100204af0>",
"<Person: 0x100206b20>"
) - (
"<Person: 0x100207910>",
"<Person: 0x1002074d0>"
)
block为什么要用copy?
首先, block是一个对象, 所以block理论上是可以retain/release的. 但是block在创建的时候它的内存是默认是分配在栈(stack)上, 而不是堆(heap)上的. 所以它的作用域仅限创建时候的当前上下文(函数, 方法...), 当你在该作用域外调用该block时, 程序就会崩溃.
![](https://img.haomeiwen.com/i2782369/9aaad8ed43b7ec7b.png)
意思就是 : 一般情况下你不需要自行调用copy或者retain一个block. 只有当你需要在block定义域以外的地方使用时才需要copy. Copy将block从内存栈区移到堆区.
其实block使用copy是MRC留下来的也算是一个传统吧, 在MRC下, 如上述, 在方法中的block创建在栈区, 使用copy就能把他放到堆区, 这样在作用域外调用该block程序就不会崩溃. 但在ARC下, 使用copy与strong其实都一样, 因为block的retain就是用copy来实现的, 所以block使用copy还能装装逼, 说明自己是从MRC下走过来的
总结
这里做出了一张图, 帮助新手弄清楚copy与mutableCopy的区别, 大神请无视_
![](https://img.haomeiwen.com/i1862021/d9694468cbad6cdc.png)
网友评论