首先,明白复制的原则:
- 复制出一个新的对象
- 对原来对象或新复制出的对象进行修改不会互相影响
然后,明白Copy
和MutableCopy
的原则
- 使用
Copy
出来的对象都是不可变对象 - 使用
MutableCopy
出来的对象都是可变对象
NSString使用Copy
NSString *oldString = [NSString stringWithFormat:@"haha"];
NSString *newString = [oldString copy];
NSLog(@"oldString:%p---newString:%p",oldString,newString);
//打印结果
oldString:0xa000000616861684---newString:0xa000000616861684
结论:对不可变对象使用Copy不产生新对象,只会进行指针拷贝,即浅拷贝,因为都是不可变对象,不存在修改之后互相影响的情况,所以系统为节约内存,只进行了指针拷贝.
NSMutableString使用Copy
NSMutableString *oldString = [NSMutableString stringWithFormat:@"haha"];
NSString *newString = [oldString copy];
[oldString appendString:@"change"];
NSLog(@"oldString:%@---newString:%@",oldString,newString);
NSLog(@"oldString:%p---newString:%p",oldString,newString);
//打印结果
oldString:hahachange---newString:haha
oldString:0x60800027ef80---newString:0xa000000616861684
结论:对可变对象使用Copy会产生新的对象,新对象为不可变对象,对新对象或原对象修改不会互相影响
NSString使用MutableCopy
NSString *oldString = [NSString stringWithFormat:@"haha"];
NSMutableString *newString = [oldString mutableCopy];
[newString appendString:@"change"];
NSLog(@"oldString:%@---newString:%@",oldString,newString);
NSLog(@"oldString:%p---newString:%p",oldString,newString);
//打印结果
oldString:haha---newString:hahachange
oldString:0xa000000616861684---newString:0x6000002688c0
结论:对不可变对象使用MutableCopy会产生新的对象,新对象为可变对象,对新对象或原对象修改不会互相影响
NSMutableString使用MutableCopy
NSMutableString *oldString = [NSMutableString stringWithFormat:@"haha"];
NSMutableString *newString = [oldString mutableCopy];
[newString appendString:@"change"];
NSLog(@"oldString:%@---newString:%@",oldString,newString);
NSLog(@"oldString:%p---newString:%p",oldString,newString);
//打印结果
oldString:haha---newString:hahachange
oldString:0x600000261240---newString:0x600000262300
结论:对可变对象使用MutableCopy会产生新的对象,新对象为可变对象,对新对象或原对象修改不会互相影响
@property中的copy使用
在普通的strong
修饰的属性生成的set
方法实现为简单赋值,即:
@property (nonatomic, strong) NSString *name;
- (void)setName:(NSString *)name{
_name = name;
}
而使用copy
修饰的属性生成的set
方法则是把传入对象拷贝一份内存赋值给成员变量,即:
@property (nonatomic, strong) NSString *name;
- (void)setName:(NSString *)name{
_name = [name copy];
}
结论:这样我们就可以达到对赋值前后的对象之间修改不会互相影响
但是这样的话就会出现一种特殊情况,当成员变量是可变类型的时候,通过copy出来的是不可变对象,赋值给成员变量后其本质上已经为不可变对象,然后我们仍会误以为其实可变对象,而调用一些可变对象的方法,此时程序会崩溃:
@property (nonatomic, copy) NSMutableString *mutableString;
self.mutableString = [NSMutableString stringWithFormat:@"test"];
//这里`_mutableString`已经是不可变字符串了,使用`appendString `方法会崩溃
[self.mutableString appendString:@"test"];
//错误提示:
-[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0xa000000747365744
结论:我们要避免对可变对象使用copy