以NSString为例,一个NSString属性用copy要优于使用strong。这同样适用于遵守NSCoding协议的不可变类(immutable class),如NSNumber、NSArray、NSSet等。他们都有一个可变(mutable)的版本。
选择使用copy的理由是,比如NSString,NSString属性可能被传入一个NSMutableString实例,这样字符串的值可能会在背后悄悄变化。(传入NSString则无所谓,不会改变)
@interface Book : NSObject @property (strong, nonatomic) NSString *title; @end
在另一个类中,我们有一个这样的方法:
- (void)stringExample { NSMutableString *bookTitle = [NSMutableString stringWithString:@"Best book ever"]; Book *book = [[Book alloc] init]; book.title = bookTitle; [bookTitle setString:@"Worst book ever"]; NSLog(@"book title %@", book.title); }1.运行后会发现,图书的标题变成了“Worst book ever”。
使用strong,属性与字符串指向同一个内存地址,只是字符串的retain计数将增加1。这意味着任何指向这个内存地址的变量都可改变这个值,本例中bookTitle变量的值改变后,title属性值也跟随变化。
2.如果我们之前使用的是copy声明title属性,图书的标题不会变,仍然是“Best book ever”。
改用copy,则会创建一个字符串副本。也就是说修改booTitle,不再会影响字符串副本值,这是多数情况下我们想要的结果。
另一个例子:
1.赋值可变版本
@interface ViewController ()
@property (nonatomic,retain)NSString *retainStr;
@property (nonatomic,copy)NSString *cStr;
@property (nonatomic,retain)NSMutableString *retainMStr;
@property (nonatomic,copy)NSMutableString *cMStr;
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSMutableString *mStr = [NSMutableString string];
[mStr setString:@"我没变"];
self.cStr = mStr;
self.cMStr = mStr;
self.retainMStr = mStr;
self.retainStr = mStr;
NSLog(@"cStr = %@",self.cStr);//我没变
NSLog(@"cMStr = %@",self.cMStr);//我没变
NSLog(@"retainStr = %@",self.retainStr);//我没变
NSLog(@"retainMStr = %@",self.retainMStr);//我没变
NSLog(@"\n");
[mStr setString:@"我变了"];
NSLog(@"cStr = %@",self.cStr);//我没变
NSLog(@"cMStr = %@",self.cMStr);//我没变
NSLog(@"retainStr = %@",self.retainStr);//我变了
NSLog(@"retainMStr = %@",self.retainMStr);//我变了
NSLog(@"\n");
如果改变一下代码:
self.retainMStr = [mStr mutableCopy];
self.retainStr = [mStr copy];
手工copy一下,则结果为4个都不变。
2.赋值不可变版本
NSString *str = @"我来了";
self.cStr = str;
self.cMStr = [strmutableCopy];
self.retainMStr = [strmutableCopy];
self.retainStr = str;
NSLog(@"str = %@",str);// 我来了
NSLog(@"cStr = %@",self.cStr);// 我来了
NSLog(@"cMStr = %@",self.cMStr);// 我来了
NSLog(@"retainStr = %@",self.retainStr);// 我来了
NSLog(@"retainMStr = %@",self.retainMStr);// 我来了
NSLog(@"\n");
str = @"我走了";
NSLog(@"str = %@",str);// 我走了
NSLog(@"cStr = %@",self.cStr);// 我来了
NSLog(@"cMStr = %@",self.cMStr);// 我来了
NSLog(@"retainStr = %@",self.retainStr);// 我来了
NSLog(@"retainMStr = %@",self.retainMStr);// 我来了
NSLog(@"\n");
运行会发现,也只有mStr变了,应该是mStr指向别的内存了
将程序改为输出%p(输出内存地址),证明了猜想。