大话strong, copy和mutablecopy

1.strong和copy的区别

通常情况下,我们在定义字符串属性的时候,会用到两种修饰词:strong和copy。但是比较规范的写法是用copy,也就是说copy要比strong更好,到底copy好在哪里?我们下面用实例来说明。

@interface ViewController ()
@property (nonatomic, copy) NSString* str1;
@property (nonatomic, strong) NSString* str2;
@end

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSMutableString* tempStr = [@"hello" mutableCopy];
    self.str1 = tempStr;
    self.str2 = tempStr;
    NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
    [tempStr appendFormat:@"world"];
    NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
  }

在上面的代码中,分别给str1和str2赋值为同一个可变字符串变量(有人可能会疑问,为什么要赋一个可变字符串,而不是一个NSString类型的?如果赋值一个NSString类型的字符串,用strong和copy也就没有什么区别了,这一点我们后面会进行总结,在这儿我们先看它们之间的差异),执行上面的代码,打印的结果如下图:


屏幕快照 2016-08-23 10.04.02 AM.png

通过打印的结果我们发现:当我改变tempStr的值的时候,str1的值没有发生变化(这个是用copy修饰的), 但是str2的值发生了改变(这个是用strong修饰的),由此我们可以假设一下,str1和tempStr不是指向同一块儿内存,而str2和tempStr指向同一块儿内存,下面来验证一下:

    NSMutableString* tempStr = [@"hello" mutableCopy];
    self.str1 = tempStr;
    self.str2 = tempStr;
    NSLog(@"temStr = %p, self.str1 = %p, self.str2 = %p",tempStr,self.str1,self.str2);
    NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
    [tempStr appendFormat:@"world"];
    NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);

只是在原来的代码中加了一行指针打印,打印结果如下:

屏幕快照 2016-08-23 10.33.25 AM.png

果然和我们假设的一致,str1和tempStr不指向同一块儿内存,而str2和tempStr指向了同一块儿内存。那么这样就会出现一个问题:本来我们定义的str2是一个NSString类型,这就意味着我们并不想str2发生改变,但是当外界赋给它一个可变的值的时候,它却因为外界值的修改而被修改,这是我们所不愿看到的。所以上面的情况用copy修饰会更好。

2.NSArray是不是也需要用copy来修饰?

看了上面的情况,是不是有人会联想到像 NSArray和NSDictionary这样的可以赋给一个可变量的属性,是不是也应该用copy来修饰?下面我们还是用实例来说明。

@interface ViewController ()
@property (nonatomic, copy) NSArray* array1;
@property (nonatomic, strong) NSArray* array2;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSMutableArray* tempArray = [@[@"hello"] mutableCopy];
    self.array1 = tempArray;
    self.array2 = tempArray;
    NSLog(@"tempArray = %p, array1 = %p, array2 = %p, ",tempArray,self.array1,self.array2);
    NSLog(@"array1 = %@, array2 = %@",self.array1,self.array2);
    [tempArray addObject:@"world"];
    NSLog(@"array1 = %@, array2 = %@",self.array1,self.array2);
   }

打印结果如下:

屏幕快照 2016-08-23 10.50.51 AM.png

从打印的结果我们依然可以得出: array1(也就是用copy修饰的)和tempArray不指向同一块儿内存,array2(也就是用strong修饰的)和tempArray指向了同一块儿内存,所以当我们修改tempArray的时候,array2的值也被修改了,这跟我们上面定义成NSArray,也就是不可变类型相违背,所以当我们定义一个像NSArray和NSDictionary这样有对应可变类型的属性的时候,都应该用copy。

可能到这儿还是有人有疑问,如果我定义的属性本身就是一个可变类型的,比如NSMutableArray,那么我是应该用strong还是copy呢?如果不出意料的话,大家用的都是strong,下面我们测一下为什么strong又比copy好。还是用实例说话。

@interface ViewController ()
@property (nonatomic, copy) NSMutableArray* array3;
@property (nonatomic, strong) NSMutableArray* array4;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
   NSMutableArray* tempArray = [NSMutableArray arrayWithObject:@"hello"];
    self.array3 = tempArray;
    self.array4 = tempArray;
    NSLog(@"tempArray = %p,array3 = %p,array4 = %p",tempArray,self.array3,self.array4);
    [tempArray addObject:@"world"];
    NSLog(@"array3 = %@,array4 = %@,",self.array3,self.array4);
 }

打印的结果如下:

屏幕快照 2016-08-23 11.19.49 AM.png

从打印的结果可以看出,array3和tempArray不是指向同一块儿内存,array4和tempArray指向同一块儿内存,所以当修改tempArray的值的时候,array4的值也跟着改了。而array4本身就是一个NSMutableArray类型,就意味着是可以被修改的,所以用strong会更好。

  • 总结一下上面的类容

用copy还是strong主要取决于开发者的意图:当你不允许让这个属性的值被外界更改,就用copy;当你允许这个属性的值被外界所更改,就用strong。

3. copy和mutablecopy

对于copy和mutablecopy的区别,需要分为两种情况来谈:给不可变属性赋值和给可变属性赋值。下面先看给不可变属性赋值的情况,依然用实例说话:

@interface ViewController ()
@property (nonatomic, copy) NSString* str3;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
 
    NSString* tempStr = @"hello";
    self.str3 = [tempStr copy]; 
    NSLog(@"tempStr_p1 = %p, str3_p1 = %p",tempStr,self.str3);
    self.str3 = [tempStr mutableCopy];
    NSLog(@"tempStr_p2 = %p, str3_p2 = %p",tempStr,self.str3);
}

打印结果如下:

屏幕快照 2016-08-23 6.18.58 PM.png
  • 由图打印的结果可以得出如下结论
    str3是不可变的类型,[tempStr copy]也是不可变的类型,把tempStr赋给str3,也就是把一个不可变的赋给一个不可变的,既然两个都不可变,也就是都不存在被修改的风险,所以用同一块儿内存就行了,没有必要再搞一块儿内存,所以会有上面的 tempStr_p1=str3_p1;
    但是[tempStr mutableCopy]是一个可变的类型,把[tempStr mutableCopy]赋给str3,也就是把一个可变的赋给了一个不可变的,但是这样就会出现一个问题:当可变的那个变量的值发生改变的时候,可能会导致不可变的那个变量的值也跟着改变,这就违背了开发者的意图,所以就要给str3重新分配一份儿内存,也就有了上面的 tempStr_p12 != str3_p2。

下面再看看给可变类型的属性赋值的情况,还是用实例说话:

@interface ViewController ()
@property (nonatomic, strong) NSMutableString* str4;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
       NSMutableString* tempStr = [NSMutableString stringWithString:@"hello"];
    self.str4 = [tempStr copy];
    NSLog(@"tempStr_p1 = %p, str4_p1 = %p",tempStr,self.str4);
    self.str4 = [tempStr mutableCopy];
    NSLog(@"tempStr_p2 = %p, str4_p2 = %p",tempStr,self.str4);
    
}

打印结果如下图

屏幕快照 2016-08-23 6.50.15 PM.png
  • 由图打印的结果可以得出如下的结论
    str4是可变的类型,[tempStr copy]其实是一个不可变的类型,把[tempStr copy]赋给str4,其实是把一个不可变的赋给了一个可变的,如果这两个还共用一块儿内存的话,当str4的值发生了改变,会导致[tempStr copy]这个不可变的变量的值也跟着变化,这样就矛盾了,所以就有了上面的 tempStr_p1 != str4_p1,也就是给str4重新搞一块儿内存,让str4在自己的那块儿内存中随便折腾而不影响别人;
    但是[tempStr mutableCopy]是一个可变的类型,把[tempStr mutableCopy]赋给str4,其实是把一个可变的赋给了一个可变的,那么可能有人会有疑问,既然都是可变的,那为何不共用同一块儿内存呢,为何 tempStr_p2 != str4_p2呢?我的理解是这样的:虽然[tempStr mutableCopy]是可变的,但是我不希望你str4来改变我,我要变我自己会变,所以还是给str4搞了一块儿新的内存,让str4自己玩自己的,不要去影响别人。

  • 本文属原创文章,转载请注明出处,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容