我们定义一个类,并为其声明两个字符串属性,如下所示:
@interface ViewController ()
@property(nonatomic, strong) NSString *strongStr;
@property(nonatomic, copy) NSString *copyedStr;
@end
上面的代码声明了两个字符串属性,其中一个内存特性是strong,一个是copy。下面我们来看看它们的区别。
首先,我们用一个不可变字符串来为这两个属性赋值,
- (void)test {
NSString *testStr = [NSString stringWithFormat:@"123"];
self.strongStr = testStr;
self.copyedStr = testStr;
NSLog(@"testStr=%p", testStr);
NSLog(@"strongStr=%p", self.strongStr);
NSLog(@"copyedStr=%p", self.copyedStr);
}
其输出结果是:
2018-02-26 13:03:22.080907+0800 tes[5408:409468] testStr=0xa000000003332313
2018-02-26 13:03:22.081044+0800 tes[5408:409468] strongStr=0xa000000003332313
2018-02-26 13:03:22.081139+0800 tes[5408:409468] copyedStr=0xa000000003332313
我们可以看到,这种情况下,不管是strong还是copy属性的对象,其指向的地址都是同一个,即为string指向的地址。
接下来,我们把testStr由不可变改为可变对象,看看会是什么结果。即将下面这一句
NSMutableString *testStr = [NSMutableString stringWithFormat:@"123"];
其输出结果是:
2018-02-26 13:03:59.758429+0800 tes[5430:412707] testStr=0x604000242190
2018-02-26 13:03:59.758555+0800 tes[5430:412707] strongStr=0x604000242190
2018-02-26 13:03:59.758648+0800 tes[5430:412707] copyedStr=0xa000000003332313
可以发现,此时copy属性字符串已不再指向testStr字符串对象,而是深拷贝了testStr字符串,并让copyStr对象指向这个字符串。
此时,我们如果去修改testStr字符串的话,可以看到:因为strongStr与testStr是指向同一对象,所以strongStr的值也会跟随着改变;而copyStr是指向另一个对象的,所以不会改变。
结论
由于NSMutableString是NSString的子类,所以一个NSString指针可以指向NSMutableString对象.
而上面的例子可以看出,当原字符串是NSString时,由于字符串是不可变的,所以,不管是strong还是copy属性的对象,都是指向原对象,copy操作只是做了次浅拷贝。
当原字符串是NSMutableString时,strong属性只是增加了源字符串的引用计数,而copy属性则是对源字符串做了次深拷贝,产生一个新的对象,且copy属性对象指向这个新的对象。另外需要注意的是,这个copy属性对象的类型始终是NSString,而不是NSMutableString,因此其是不可变的。
这里还有一个性能问题,即在源字符串是NSMutableString,strong是单纯的增加对象的引用计数,而copy操作是执行了一深拷贝,所以性能上会有所差异。而如果原字符串是NSString时,则没有这个问题。
所以,我们一般采用copy修饰字符串,防止修改NSMutableString类型的字符串导致原来的数据被修改掉.