之前在项目的model中,也都没有在意这个问题,直接所有的NSString属性都是用的strong来修饰的,其实这是不对的,后来经同事提点,说是最好model里面NSSring属性都要用copy来修饰,下面我们就来探究一下其中的原因。
结论
首先就直接上结论:
当我们十分确定,要给属性NSString赋一个不可变的值时,用strong。如果使用copy来修饰属性,在进行赋值的时候,会先做一个类型判断,如果赋的值是一个不可变的字符串,则走strong的策略,进行的是浅拷贝;如果是可变的字符串,则进行深拷贝创建一个新的对象。所以如果我们确定是给属性赋值一个不可变的值,就不用copy再多去判断一遍类型,因为如果是很多的NSString属性需要赋值,会极大的增加系统开销。所以用strong在此情况下可以提升性能。
但是很多情况下我们并不能确定要赋的值是什么类型的,所以我们还是使用copy来修饰,这样保证了安全性。因为如果赋值的可变的字符串,当它发生变化时,用strong修饰的属性的值也会跟着变化;而copy修饰的属性,则因为是深拷贝而不会变化。
代码示例
声明两个属性变量
@property (nonatomic, strong) NSString *strongStr;
@property (nonatomic, copy) NSString *copyedStr;
//不可变字符串赋值
- (void)testString {
NSString *string = [NSString stringWithFormat:@"lalala"];
self.strongStr = string;
self.copyedStr = string;
NSLog(@"origin string: %p, %p", string, &string);
NSLog(@"strong string: %p, %p", _strongStr, &_strongStr);
NSLog(@"copyed string: %p, %p", _copyedStr, &_copyedStr);
}
可以看到结果如下:
这种情况下,不管是strong还是copy属性的对象,其指向的地址都是同一个,即为string指向的地址。
而如果将string换成NSMutableString:
//可变字符串赋值
- (void)testMutbleString {
NSMutableString *mutbleString = [NSMutableString stringWithFormat:@"hahaha"];
self.strongStr = mutbleString;
self.copyedStr = mutbleString;
// [mutbleString appendString:@" wawawa"];
NSLog(@"mut origin string: %p, %p", mutbleString, &mutbleString);
NSLog(@"mut strong string: %p, %p", _strongStr, &_strongStr);
NSLog(@"mut copyed string: %p, %p", _copyedStr, &_copyedStr);
}
可以发现,此时copy属性字符串已不再指向string字符串对象,而是深拷贝了string字符串,并让_copyedStr对象指向这个字符串。
而如果此时我们改变mutbleString的值,即放开上面代码中的注释[mutbleString appendString:@" wawawa"];
可以看到如下图,_strongStr因为与string指向同一对象,所以其值跟随string发生了变化;而_copyedStr因为创建了一个新的对象,所以不会跟随string的值变化而变化。
参考文章:
https://southpeak.github.io/2015/05/10/ios-techset-1/
https://www.jianshu.com/p/a4874c788f78