在 iOS 开发中我们在使用 @property 定义属性的时候经常会使用 copy 属性来个对一个 NSString 或者 NSArray,NSDictionary 来进行修饰, 然而许多同学只是在别人的代码上看到, 学习这样使用.
也有一部分同学是大概了解一点, 主要是为了让该对象持有赋值对象的副本, 避免被赋值对象在其他地方被修改, 造成错误(我也是属于这一类..), 该文章主要是为了提升自己对 copy 属性的理解, 并且区分什么时候使用才正确.
1. 为什么要使用 copy?
因为父类指针可以指向子类对象, 使用 copy 修饰对象的话, 无论赋值对象是可变还是不可变的, 对象本身持有的都是一个不可变的副本, 这样就避免外界的影响.(其实这一个话是有点问题的, 用 copy 修饰的对象如果传入一个不可变对象, 其实也只是单纯的指针拷贝, 指向的还是同一块内存, 但是个人水平有限, 对于内存问题不敢妄下定论)
如果我们使用 strong 修饰对象的话, 该对象可能会指向一个可变对象, 如果这个可变对象发生改变的话, 使用 strong 修饰的对象也会受到影响.
我们在日常使用 NSString 的时候, 为了避免对象在某个地方被改变, 而开发者也无法发现这种情况出现, 我们经常都是使用 copy 修饰对象, 这个时候即使传入一个 "可变" 对象, 这个时候我们这个 NSString 对象持有的只是该 "可变" 对象的一个 "不可变" 的副本.
2. 在那些地方使用 copy
首先这里要区分浅拷贝和深拷贝, 集合对象和非集合对象
浅拷贝: 一般理解为指针拷贝, 就是会拷贝一个新的指针, 但是指针指向的内存地址依然保持不变
深拷贝: 可以理解为内容拷贝, 也就是说不仅会拷贝一份指针, 同时对内容也会进行一次拷贝, 相当于复制了一个副本
下面开始区分什么时候回进行浅拷贝, 什么时候会进行深拷贝(按照集合类型和非集合类型讨论)
对于非集合对象:
操作 | 结果 |
---|---|
[不可变对象 copy] | 浅拷贝 |
[不可变对象 mutableCopy] | 深拷贝 |
[可变对象 copy] | 深拷贝 |
[可变对象 mutableCopy] | 深拷贝 |
就是说我们一般使用 copy 修饰一个 NSString 的时候, 传入另外一个 NSString 的时候, 只会复制一份新的指针, 指向的还是同一个地址. 但是由于传入的 NSString 是一个不可变对象, 我们也不用担心它在其它地方被随意更改了.
- @property(nonatomic,strong)NSString *strongString;
- NSMutableString *mutString = [NSMutableString stringWithString:@"milan"];
- self.strongString = [mutString copy];
类似以上操作, 用 Strong 修饰的 NSString 对象所持有的也是一个 "不可变" 的副本
对于集合类型对象:
操作 | 结果 |
---|---|
[不可变对象 copy] | 浅拷贝 |
[不可变对象 mutableCopy] | 深拷贝 |
[可变对象 copy] | 深拷贝 |
[可变对象 mutableCopy] | 深拷贝 |
注意! 对于集合类型的对象, 内容拷贝的只有对象本身, 对于集合类型内部的元素只进行浅拷贝, 就是只拷贝指针
对于在什么地方使用 Copy 修饰对象, 没有硬性要求, 理解 copy 以及 mutableCopy 以后, 在何处使用自行判断就可以, 当然为了避免自己很多时候考虑不周, 我们一般建议使用 copy 修饰实例变量
3. 使用 copy 的注意点
- @property (nonatomic,copy)NSMutableArray *mutArray;
- NSMutableArray *testArray = [NSMutableArray arrayWithObject:@"milan"];
- self.mutArray = [testArray copy];
对于以上的操作在一般使用上是没有问题的, 但是当你的 mutArray 想要插入或删除内容的时候会报错, 因为 [testArray copy] 赋值给 mutArray 以后, 其实它持有的是一个 "不可变" 的副本, 即使你本身定义为一个可变对象.
最后
以上内容是参考别人的东西并加上自己的理解得出的, 若有错误之处请指出, 并且对于使用 copy 需要注意的地方, 希望有更多的发现
来源: http://www.jianshu.com/p/682457c922c5