copy属性的一个好处

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

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

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

 

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












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值