这个问题既是一个面试题,也是开发中经常遇到的问题,NSString 属性到底用copy 还是 strong ?其实如果明白的两者的区别也就不会疑惑了,其实都可以,只是如果你不明白两者的实质的区别,有可能会出现难以发现的异常。但是我们遇到的又很少所有经常用哪个都行,但是不知道有何区别,在此我实际验证一下。记录这个经常模糊不清的问题。
1.快速搭建一个demo
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(@"\n");
// 验证不可变对象NSString
[self test];
// 验证可变对象NSMutableString
// [self test22];
// 如果用NSString赋值的话strong和copy(此刻是浅拷贝)是没有区别的
// 如果用NSMutableString赋值的话strong没有只是增加了str1的计数器,并没有开辟新的内存
// copy的话开辟了新的内存,对string的内容进行修改的话,strong的字符串内容改变了,而copy的并没有改变
// 如果需要改变的话可以用strong,如果不需要改变的话用copy
// 所以属性指向可变对象时应注意;
}
- (void)test{
NSString *string = [NSString stringWithFormat:@"测试文字"];//注释1
self.strongStr = string;
self.copyssStr = string;
NSLog(@"String:%@ strongStr:%@ copyssStr:%@",string,self.strongStr,self.copyssStr);
NSLog(@"String : %p, %p", string, &string);
NSLog(@"Strong属性: %p, %p",_strongStr, &_strongStr);
NSLog(@"Copy 属性: %p, %p",_copyssStr, &_copyssStr);
NSLog(@"\n");
string = @"我变了,你没变";
NSLog(@"我变 String:%@ strongStr:%@ copyssStr:%@",string,self.strongStr,self.copyssStr);
NSLog(@"我变 String : %p, %p", string, &string);
NSLog(@"我变 Strong属性: %p, %p",_strongStr, &_strongStr);
NSLog(@"我变 Copy 属性: %p, %p",_copyssStr, &_copyssStr);
// NSString总结:用NSString赋值的话strong和copy(此刻是浅拷贝)是没有区别的;从新赋值,相当于指向了新的一个对象,string指向变了,而strong和copy指针(此刻是浅拷贝
// 还是指向的原来的对象,所以说不变。
// 所以不可变对象的copy 和strong 与可变对象的copy 一样效果,赋值后copy 和 strong 指针指向的值都不变;
/*
1. 当原字符串是NSMutableString时,Strong属性只是增加了原字符串的引用计数,而Copy属性则是对原字符串做了次深拷贝,产生一个新的对象,且Copy属性对象指向这个新的对象,且这个Copy属性对象的类型始终是NSString,而不是NSMutableString,因此其是不可变的。
2. 这里还有一个性能问题,即在原字符串是NSMutableString,Strong是单纯的增加对象的引用计数,而Copy操作是执行了一次深拷贝,所以性能上会有所差异(虽然不大)。如果原字符串是NSString时,则没有这个问题。
所以,在声明NSString属性时,到底是选择strong还是copy,可以根据实际情况来定。不过,一般我们将对象声明为NSString时,都不希望它改变,所以大多数情况下,我们建议用copy,以免因可变字符串的修改导致的一些非预期问题。
*/
}
- (void)test22{
//
NSMutableString *string = [NSMutableString stringWithFormat:@"测试文字"];
self.strongStr = string;
self.copyssStr = string;
NSLog(@"String:%@ strongStr:%@ copyssStr:%@",string,self.strongStr,self.copyssStr);
NSLog(@"String 地址: %p, %p", string, &string);
NSLog(@"Strong 地址: %p, %p",_strongStr, &_strongStr);
NSLog(@"Copy 地址: %p, %p",_copyssStr, &_copyssStr);
NSLog(@"\n");
[string appendString:@"我变了,你没变"];
NSLog(@"append 后 String:%@ strongStr:%@ copyssStr:%@",string,self.strongStr,self.copyssStr);
NSLog(@"append 后 String 地址: %p, %p", string, &string);
NSLog(@"append 后 Strong 地址: %p, %p",_strongStr, &_strongStr);
NSLog(@"append 后 Copy 地址: %p, %p",_copyssStr, &_copyssStr);
NSLog(@"\n");
// NSMutableString总结:
// 如果string 的指针不变,内存地址不变,值变化,则strongStr 的值跟着变化,指针不变,地址不变;而copyssStr 则不会任何变化;
string = [NSMutableString stringWithFormat:@"ccvcc"];
NSLog(@"Mutable 后 String:%@ strongStr:%@ copyssStr:%@",string,self.strongStr,self.copyssStr);
NSLog(@"Mutable 后 String 地址: %p, %p", string, &string);
NSLog(@"Mutable 后 Strong 地址: %p, %p",_strongStr, &_strongStr);
NSLog(@"Mutable 后 Copy 地址: %p, %p",_copyssStr, &_copyssStr);
// 总结:Mutable 相当于重新alloc一个对象, string 指针的指向变了,指向了新的对象的地址,strongStr 指针不变,指向的还是原来对象的地址,地址不变;而copyssStr已经去string没有关系,则不会任何变化;
// 这里我想验证下strongStr 指向的是原来的还是新的对象的
[self performSelector:@selector(shows) withObject:nil afterDelay:10];
}
- (void)shows {
NSLog(@"shows 后 strongStr:%@ copyssStr:%@",self.strongStr,self.copyssStr);
}
上面代码中有自己对比得出的结论,推出多用copy 是因为我们使用属性一般是全局的,不期望 *string被改变时,也改变了copy 属性的值。我们希望的是self.copyssStr = @"";来改变
参考:https://www.jianshu.com/p/8bbe01e53114
:https://blog.csdn.net/itianyi/article/details/9018567
:https://blog.csdn.net/summer_csdn123/article/details/52190879
:https://www.jianshu.com/p/b3873ac9259b