- 介绍copy和mutableCopy
- 介绍深拷贝与浅拷贝
- block为何要用copy
- copy相对于直接赋值的好处
- 总结
内存的栈区 : 由编译器自动分配释放, 存放函数的参数值, 局部变量的值等. 其操做方式相似于数据结构中的栈. 程序员
内存的堆区 : 通常由程序员分配释放, 若程序员不释放, 程序结束时可能由OS回收. 注意它与数据结构中的堆是两回事, 分配方式却是相似于链表.数组
若是你想要建立一个对象, 该对象与源对象的内容一致, 那么你能够考虑用拷贝(copy或mutableCopy), 首先, 我将会利用字符串, 数组, 字典这三种常见的对象来讲明copy与mutableCopy的区别. 数据结构
NSString *string = @"Jerry";
[string copy] --> 拷贝出内容为Jerry的NSString类型的字符串
[string mutableCopy] --> 拷贝出内容为Jerry的NSMutableString类型的字符串
NSDictionary *dict = @{@"name" : @"Jerry"};
[dict copy] --> 拷贝出内容与dict相同的NSDictionary类型的字典
[dict mutableCopy] --> 拷贝出内容与dict相同的NSMutableDictionary类型的字典
NSArray *array = @[@"Jerry"];
[array copy] --> 拷贝出内容与array相同的NSArray类型的数组
[array mutableCopy] --> 拷贝出内容与array相同的NSMutableArray类型的数组
- copy拷贝出来的对象类型老是不可变类型(例如, NSString, NSDictionary, NSArray等等)
- mutableCopy拷贝出来的对象类型老是可变类型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)
何为深拷贝, 何为浅拷贝?函数
深拷贝 : 拷贝出来的对象与源对象地址不一致! 这意味着我修改拷贝对象的值对源对象的值没有任何影响.
浅拷贝 : 拷贝出来的对象与源对象地址一致! 这意味着我修改拷贝对象的值会直接影响到源对象.测试
这里须要纠正网上一些错误的观点(如下为错误观点)3d
copy都是浅拷贝, mutableCopy都是深拷贝
咱们知道, 当咱们用copy从一个可变对象拷贝出一个不可变对象时, 这种状况就属于深拷贝而不是浅拷贝!!指针
对于NSString对象, 确实深拷贝就是深拷贝, 浅拷贝就是浅拷贝, 没有任何异议.
可是对于NSArray, NSDictionary, NSSet这些容器类的对象呢? 固然浅拷贝依然是指针拷贝, 那深拷贝意味着连同容器及其容器内的对象一并拷贝吗? 仍是只拷贝容器对象, 对容器内的对象则只是简单引用呢? 这里有两种状况, 我姑且把它称为不彻底深拷贝与彻底深拷贝对象
不彻底深拷贝就是只拷贝容器对象(拷贝一个壳), 而对于容器内的对象则只保存一份引用. blog
因此咱们知道, 就算咱们修改copyArray不会影响到源array, 可是我经过copyArray修改数组内的object, 对应地源array内的object也会随之修改, 你们能够自行测试. 图片
彻底深拷贝就是连同容器内的对象在内, 完彻底全拷贝一份出来
经过图片能够很清楚地知道, 这种状况下不管是修改copyArray仍是经过copyArray修改数组内的object, 对源array都不会形成半点影响.
// 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>"
)
这样就能办到彻底深拷贝的目的了.
ps : 官方文档说明copy方法内部默认会调用copyWithZone方法的, 可是NSArray由于未知的缘由致使其copy方法不会调用copyWithZone (多是由于OC中已经废弃了zone这个概念, 苹果官方文档有说), 因此这里我就利用分类重写了NSArray的copy方法, 实际上苹果并不推荐这么作.
首先, block是一个对象, 因此block理论上是能够retain/release的. 可是block在建立的时候它的内存是默认是分配在栈(stack)上, 而不是堆(heap)上的. 因此它的做用域仅限建立时候的当前上下文(函数, 方法...), 当你在该做用域外调用该block时, 程序就会崩溃.
意思就是 : 通常状况下你不须要自行调用copy或者retain一个block. 只有当你须要在block定义域之外的地方使用时才须要copy. Copy将block从内存栈区移到堆区.
其实block使用copy是MRC留下来的也算是一个传统吧, 在MRC下, 如上述, 在方法中的block建立在栈区, 使用copy就能把他放到堆区, 这样在做用域外调用该block程序就不会崩溃. 但在ARC下, 使用copy与strong其实都同样, 由于block的retain就是用copy来实现的, 因此block使用copy还能装装逼, 说明本身是从MRC下走过来的..嘿嘿
看看如下代码 :
你们猜猜控制台输出是啥? 是( Kobe ), ( Kobe, McGrady )吗?
错了错了!!!
array = (
Kobe,
McGragy
), mArray = (
Kobe,
McGragy
)
你们再来猜一下输出会是什么?
没错!
array = (
Kobe
), mArray = (
Kobe,
McGragy
)
这里作出了一张图, 帮助新手弄清楚copy与mutableCopy的区别, 大神请无视^_^
若是可以在你的工程中正确使用copy, 将会对你的程序有不小的帮助.细节决定成败嘛!!