copy属性的一个好处

来源:互联网 发布:阿里云9.9半年学生机 编辑:程序博客网 时间:2024/05/06 20:27

以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");

    

    [mStrsetString:@"我变了"];


    NSLog(@"cStr = %@",self.cStr);//我没变

    NSLog(@"cMStr = %@",self.cMStr);//我没变

    NSLog(@"retainStr = %@",self.retainStr);//我变了

    NSLog(@"retainMStr = %@",self.retainMStr);//我变了

    NSLog(@"\n");

}
可见,只有使用了copy的两个仍然没有改变,使用retain的两个都悄悄的变了。

如果改变一下代码:

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");

可见,只有str本身改变了,4个变量指向的值都没变。

个人猜想:

1.赋值可变类型,用的[mStrsetString:@"我变了"];
是把原来为“我没变”的那块内存的内容改成了“我变了”,retainStr和retainMStr也还指向
这块内存,因此这两个也跟着变成“我变了”。
2.赋值不可变类型,用的str = @"我走了";
是又开辟了一块内存,内容为“我走了”,str指向它,retainStr和retainMStr还指向原来
的”我来了“的内存,因此只有str改变了。(内存泄漏)
3.在赋值可变类型中改一下代码:
[mStrsetString:@"我变了"];改为mStr = @"我变了";
会警告,不兼容的assign   from  NSString  to  NSMutableString

运行会发现,也只有mStr变了,应该是mStr指向别的内存了

 

将程序改为输出%p(输出内存地址),证明了猜想。












原创粉丝点击