@property(nonatomic,retain)NSString *str ; @property(nonatomic,copy)NSString *str2 ; <span style="color:#ff0000;">NSString</span> *tmp1=[[NSString alloc] initWithFormat:@"tmp1"]; self.str=tmp1; NSLog(@"%@,address:%p,retainCount:%d",tmp1,tmp1,tmp1.retainCount); NSLog(@"%@,address:%p,retainCount:%d",self.str,self.str,self.str.retainCount); [tmp1 release]; <span style="color:#ff0000;">NSString</span> *tmp2=[[NSString alloc] initWithFormat:@"tmp2"]; self.str2=tmp2; NSLog(@"%@,address:%p,retainCount:%d",tmp2,tmp2,tmp2.retainCount); NSLog(@"%@,address:%p,retainCount:%d",self.str2,self.str2,self.str2.retainCount); [tmp2 release];输出结果:
[1619:607] tmp1,address:0xca4d500,retainCount:2
[1619:607] tmp1,address:0xca4d500,retainCount:2
[1619:607] tmp2,address:0xca11360,retainCount:2
[1619:607] tmp2,address:0xca11360,retainCount:2
由以上可以看出,NSString类型的属性,不管是retain还是copy,当用一个NSString 不可变类型变量赋值时,其安全性、内存管理都一样;@property(nonatomic,retain)NSString *str ; @property(nonatomic,copy)NSString *str2 ; <span style="color:#ff0000;">NSMutableString</span> *tmp1=[[NSMutableString alloc] initWithFormat:@"tmp1"]; self.str=tmp1; NSLog(@"%@,address:%p,retainCount:%d",tmp1,tmp1,tmp1.retainCount); NSLog(@"%@,address:%p,retainCount:%d",self.str,self.str,self.str.retainCount); [tmp1 release]; <span style="color:#ff0000;">NSMutableString</span> *tmp2=[[NSMutableString alloc] initWithFormat:@"tmp2"]; self.str2=tmp2; NSLog(@"%@,address:%p,retainCount:%d",tmp2,tmp2,tmp2.retainCount); NSLog(@"%@,address:%p,retainCount:%d",self.str2,self.str2,self.str2.retainCount); [tmp2 release];输出结果:
[1643:607] tmp1,address:0xc8389c0,retainCount:2
[1643:607] tmp1,address:0xc8389c0,retainCount:2
[1643:607] tmp2,address:0xc836500,retainCount:1
[1643:607] tmp2,address:0xc824130,retainCount:1
由以上可以看出,NSString类型的属性,用retain修饰,当用一个NSMutableString 可变类型变量赋值时,其内存地址一样,只有一份拷贝;用copy修饰时,内存地址变了,此时拥有两份拷贝。为了更好的看出区别,我们作如下测试:
例3:
@property(nonatomic,retain)NSString *str ; @property(nonatomic,copy)NSString *str2 ; <span style="color:#ff0000;">NSMutableString</span> *tmp1=[[NSMutableString alloc] initWithFormat:@"tmp1"]; self.str=tmp1; <span style="color:#3333ff;">[tmp1 appendString:@"AAA"];</span> NSLog(@"%@,address:%p,retainCount:%d",tmp1,tmp1,tmp1.retainCount); NSLog(@"%@,address:%p,retainCount:%d",self.str,self.str,self.str.retainCount); [tmp1 release]; <span style="color:#ff0000;">NSMutableString</span> *tmp2=[[NSMutableString alloc] initWithFormat:@"tmp2"]; self.str2=tmp2; <span style="color:#3333ff;">[tmp2 appendString:@"BBB"];</span> NSLog(@"%@,address:%p,retainCount:%d",tmp2,tmp2,tmp2.retainCount); NSLog(@"%@,address:%p,retainCount:%d",self.str2,self.str2,self.str2.retainCount); [tmp2 release];输出结果:
[1673:607] tmp1AAA,address:0xce55930,retainCount:2
[1673:607] tmp1AAA,address:0xce55930,retainCount:2
[1673:607] tmp2BBB,address:0xce55970,retainCount:1
[1673:607] tmp2,address:0xce559b0,retainCount:1
由以上可以看出,当用可变类型变量赋值成员属性后,再对可变类型的变量进行了修改,那么retain修饰的,也同样会被修改;copy修饰的,因为是对象的拷贝,所以,不会同步被外界变量所修改。综合以上实验,可以得出结论,如果为成员变量赋值时,使用的是不可变的变量,那么retain和copy从内存管理上来说,其效果是一样的,没有什么使用的区别。如果使用的是可变变量对属性进行赋值,那么retain修饰的属性值就有可能被修改的可能(这往往不是我们想要的结果),而使用copy修饰的属性值就不会被修改。故:官方的sdk中,NSString 类型都是copy修饰。
建议:NSString 属性,请使用copy修饰。(当然,如果你想让你的属性值跟着变量的变化而变化,那就用retain吧)
NSString *tmp1=[[NSString alloc] initWithFormat:@"tmp1"]; NSString *copy1= [tmp1 copy]; NSMutableString *mutableCopy1=[tmp1 mutableCopy]; NSLog(@"tmp1:%p,copy1:%p,mutableCopy1:%p",tmp1,copy1,mutableCopy1); [tmp1 release]; NSMutableString *tmp2=[[NSMutableString alloc] initWithFormat:@"tmp2"]; NSString *copy2= [tmp2 copy]; NSMutableString *mutableCopy2=[tmp2 mutableCopy]; NSLog(@"tmp2:%p,copy2:%p,mutableCopy2:%p",tmp2,copy2,mutableCopy2); [tmp1 release];输出结果:
[1805:607] tmp1:0xc833dd0,copy1:0xc833dd0,mutableCopy1:0xc833db0
[1805:607] tmp2:0xc826fb0,copy2:0xc835490,mutableCopy2:0xc8354a0
建议:记住一点即可,如果复制的是不可变类型,那么copy并没有开辟新的内存,而是进行了一次浅拷贝。当然了,在实际应用中,copy返回的是不可变对象,mutableCopy返回的是可变对象,除此之外,其他都不影响使用。NSString *tmp=[[NSString alloc] initWithString:@"aaa"]; //这里等同于: tmp=@"aaa"; NSLog(@"%d",tmp.retainCount); [tmp retain]; NSLog(@"%d",tmp.retainCount); [tmp release]; NSLog(@"%d",tmp.retainCount); _str=tmp; //str为retain修饰的成员属性 _str2=tmp; //str2为copy修饰的成员属性 NSLog(@"%d,%d",_str.retainCount,_str2.retainCount);输出结果:
2016:607] -1
[2016:607] -1
[2016:607] -1
[2016:607] -1,-1
这里,我们可以看到输出结果都为-1,这是因为 @"aaa" 其实是分配在常量存储区,系统不会对齐回收,也不会对齐进行引用计数。NSArray *tmpArray=@[@1,@2]; // tmpArray retainCount =1;
self.array=tmpArray; // 赋值方法1: self.array retainCount =2; 推荐
_array=tmpArray; //赋值方法2: self.array retainCount =1; 不推荐