有关copy的几个概念
1. 拷贝
- 就是复制,产生副本,让原对象和副本相互独立,互不影响
2. 不可变拷贝(copy)
即copy
方法,无论原对象是否可变,都产生不可变副本
3. 可变拷贝(mutableCopy)
即mutableCopy
方法,无论原对象是否可变,都产生可变副本
举个例子
NSString *str = @"hello world";
[str copy]; // 拷贝出内容为hello world的NSString类型的字符串
[str mutableCopy]; // 拷贝出内容为hello world的NSMuttableString类型的字符串
4. 深拷贝
内容拷贝,会产生新的对象
- 拷贝出来的对象与原对象的地址不一样,修改拷贝对象的值对原对象不会有影响
- 深拷贝就是拷贝整个对象内容到另一块内存中
5. 浅拷贝
指针拷贝,不产生新的对象
- 拷贝出来的对象与原对象的地址一致,修改拷贝对象的值对原对象会有影响
- 浅拷贝就是在原对象的基础上引用计数+1
注意点
由上可知:copy
和深拷贝是两个概念!!!
- 原对象不可变时,
copy
方法就是浅拷贝 - 原对象可变时,
copy
方法就是深拷贝 mutableCopy
方法无论原对象可变还是不可变,都是深拷贝
安全性
1. 不希望对象无意间被修改
举个例子
@property(nonatomic,strong)NSString *str; //strong修饰
NSMutableString *mutableStr = [NSMutableString stringWithFormat:@"123"];
self.str = mutableStr;
NSLog(@"%@----%p", self.str,self.str);
NSLog(@"%@----%p", mutableStr,mutableStr);
[mutableStr appendString:@"456"]; //修改mutableStr
NSLog(@"%@----%p", self.str,self.str);
NSLog(@"%@----%p", mutableStr,mutableStr);
输出结果
2021-04-04 11:34:23.227973+0800 copy示例[2344:73458] 123----0x6000035c35a0
2021-04-04 11:34:23.228096+0800 copy示例[2344:73458] 123----0x6000035c35a0
2021-04-04 11:34:23.228187+0800 copy示例[2344:73458] 123456----0x6000035c35a0
2021-04-04 11:34:23.228268+0800 copy示例[2344:73458] 123456----0x6000035c35a0
可以看到当你修改mutableStr
时,会导致str
也被改变,显然有时候是我们并不希望看到的,如果我们的需求是当改变mutableStr
时str
不会被影响,则应当使用copy
修饰
上述代码第一行改为@property(nonatomic,copy)NSString *str;
,其余部分不变,结果如下
2021-04-04 11:38:04.092095+0800 copy示例[2388:76204] 123----0xc65d21ed94e36c08
2021-04-04 11:38:04.092227+0800 copy示例[2388:76204] 123----0x600000943ed0
2021-04-04 11:38:04.092324+0800 copy示例[2388:76204] 123----0xc65d21ed94e36c08
2021-04-04 11:38:04.092471+0800 copy示例[2388:76204] 123456----0x600000943ed0
属性由strong修饰时,将可变字符串赋值给该属性,那么属性和可变字符串指向的是同一对象,修改可变字符串时,属性也会被修改,为了防止属性在其他地方被不经意间修改,我们使用copy修饰符
2. 对象的可变和不可变性质发生了改变,导致使用方法出错
举个例子
@property(nonatomic,copy)NSMutableString *mutableString; //copy修饰的可变字符串
NSMutableString *str = [NSMutableString stringWithFormat:@"1234"]; //可变字符串1234
self.mutableString = str; //将str赋给mutableString
NSLog(@"string:%@ --- mutableString:%@",str,self.mutableString);
[self.mutableString appendString:@"5678"];
NSLog(@"string:%@ --- mutableString:%@",str,self.mutableString);
输出如下
string:1234 --- mutableString:1234
unrecognized selector sent to instance
在这里其实出错的关键点在于 self.mutableString = str;
和[self.mutableString appendString:@"5678"];
self.mutableString = str;
这行代码其实就是[self.mutableString setMutableString:str];
,具体实现如下
-(void)setMutableString:(NSMutableString *)mutableString{
if (_mutableString != mutableString) {
[_mutableString release];
_mutableString = [mutableString copy];
}
}
主要的代码_mutableString = [mutableString copy];
- 其中的
mutableString
是传入进来的参数str
- 使用
copy
方法是因为属性由copy
修饰 - 因为
str
本身是可变字符串,因此可变字符串copy
得到的值是不可变对象,即[mutableString copy]
得到的是不可变对象 mutableString
本身虽然一开始定义的是可变字符串,但是不可变对象赋值给了_mutableString
,因此其也还是一个不可变字符串了
而下面又对如今不可变字符串mutableString
进行了[self.mutableString appendString:@"5678"];
- 不可变对象是没有
appendString
方法的,所以报错unrecognized selector sent to instance
可变字符串copy后得到的是不可变字符串,即使是赋值给可变属性,属性其实是不可变的,但我们以为该属性是可变的,因此我们可能会使用错误的方法
参考博客