今天对 NSString
copy
与 strong
属性进行一次在ARC模式下的详解,与MRC模式下,主要是retain
引用计数的问题 (+1
,不+1
,加多少个1
,跟你没有半毛钱的关系,😆此处废话,忽略)。
copy
属性的意思就是复制一份给自己,strong
属性就是强引用。很好理解,我们先来看看效果。
@property (nonatomic,copy) NSString *c_String;
@property (nonatomic,strong) NSString *s_String;
定义一个可变的字符串tempString
,分别对c_String
、s_String
进行赋值,然后对它们的值、变量的内存地址、变量的地址进行打印。
NSMutableString *tempString = [NSMutableString stringWithFormat:@"original"];
self.s_String = tempString;
self.c_String = tempString;
// before change
NSLog(@"tempString:%@ strongString:%@ copyString:%@",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",&tempString,&_s_String,&_c_String);
[tempString appendString:@"change"];
// after change
NSLog(@"tempString:%@ strongString:%@ copyString:%@",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",&tempString,&_s_String,&_c_String);
下面是打印结果👇
2017-09-11 22:42:16.981 Refreshing_demo1[2043:102101] tempString:original strongString:original copyString:original
2017-09-11 22:42:16.982 Refreshing_demo1[2043:102101] tempString:0x6080000756c0 strongString:0x6080000756c0 copyString:0xa000c505a04b2028
2017-09-11 22:42:16.982 Refreshing_demo1[2043:102101] tempString:0x7fff58006738 strongString:0x7fc6d4d0d0b0 copyString:0x7fc6d4d0d0a8
2017-09-11 22:42:16.982 Refreshing_demo1[2043:102101] tempString:originalchange strongString:originalchange copyString:original
2017-09-11 22:42:16.982 Refreshing_demo1[2043:102101] tempString:0x6080000756c0 strongString:0x6080000756c0 copyString:0xa000c505a04b2028
2017-09-11 22:42:16.983 Refreshing_demo1[2043:102101] tempString:0x7fff58006738 strongString:0x7fc6d4d0d0b0 copyString:0x7fc6d4d0d0a8
由此我们可以看到结果了,copy
属性并没有改变自己的内存地址和值,而strong
属性的内存地址指向了tempString
。这样应该很好的理解两个属性的差异了吧。可以根据自己的项目需要进行相应的操作,不过一般大家都是用copy
的,(做自己不好吗,跟别人一样没意思 ,hahaha...)
无他,都不想跳进坑里面而已。我们再看看把tempString
换成 NSString
类型会怎么样。
NSString *tempString = [NSString stringWithFormat:@"original"];
self.s_String = tempString;
self.c_String = tempString;
NSLog(@"tempString:%@ strongString:%@ copyString:%@",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",&tempString,&_s_String,&_c_String);
tempString = @"change";
NSLog(@"tempString:%@ strongString:%@ copyString:%@",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",&tempString,&_s_String,&_c_String);
2017-09-11 23:02:34.166 Refreshing_demo1[2114:108457] tempString:original strongString:original copyString:original
2017-09-11 23:02:34.166 Refreshing_demo1[2114:108457] tempString:0xa000c505a04b2028 strongString:0xa000c505a04b2028 copyString:0xa000c505a04b2028
2017-09-11 23:02:34.166 Refreshing_demo1[2114:108457] tempString:0x7fff5f4bc738 strongString:0x7f9990d0c8f0 copyString:0x7f9990d0c8e8
2017-09-11 23:02:34.167 Refreshing_demo1[2114:108457] tempString:change strongString:original copyString:original
2017-09-11 23:02:34.167 Refreshing_demo1[2114:108457] tempString:0x100757b90 strongString:0xa000c505a04b2028 copyString:0xa000c505a04b2028
2017-09-11 23:02:34.167 Refreshing_demo1[2114:108457] tempString:0x7fff5f4bc738 strongString:0x7f9990d0c8f0 copyString:0x7f9990d0c8e8
如果在这样子的一个情况下,copy
与strong
属性并不会有什么分别,所以有时候我们把字符串定义成copy
或者strong
,都不会有什么影响,不过我们写代码还是要严谨一点,该用什么就用什么。
接下来我们看看下面这种的请写法会怎么样。
NSMutableString *tempString = [NSMutableString stringWithFormat:@"original"];
_s_String = tempString;
_c_String = tempString;
NSLog(@"tempString:%@ strongString:%@ copyString:%@",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",&tempString,&_s_String,&_c_String);
[tempString appendString:@"change"];
NSLog(@"tempString:%@ strongString:%@ copyString:%@",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",tempString,_s_String,_c_String);
NSLog(@"tempString:%p strongString:%p copyString:%p",&tempString,&_s_String,&_c_String);
2017-09-11 23:15:51.344 Refreshing_demo1[2172:112713] tempString:original strongString:original copyString:original
2017-09-11 23:15:51.345 Refreshing_demo1[2172:112713] tempString:0x6080000795c0 strongString:0x6080000795c0 copyString:0x6080000795c0
2017-09-11 23:15:51.345 Refreshing_demo1[2172:112713] tempString:0x7fff5cb3b738 strongString:0x7fc545d0b6d0 copyString:0x7fc545d0b6c8
2017-09-11 23:15:51.345 Refreshing_demo1[2172:112713] tempString:originalchange strongString:originalchange copyString:originalchange
2017-09-11 23:15:51.345 Refreshing_demo1[2172:112713] tempString:0x6080000795c0 strongString:0x6080000795c0 copyString:0x6080000795c0
2017-09-11 23:15:51.346 Refreshing_demo1[2172:112713] tempString:0x7fff5cb3b738 strongString:0x7fc545d0b6d0 copyString:0x7fc545d0b6c8
如果我们不用self.
点语法,这样就不会调用 getter
setter
方法,copy
也就不会起作用了,连class
类型都发生了变化,有时候因为类型发生了变化,导致程序无法识别而crash掉。
以下是这位开发者对于self
跟下划线_
的讲解
[钟颖Cyan](https://www.zhihu.com/people/ios_dev)
iOS/Mac 开发者,Pin / TodayMind / 小历
_xxx访问的是xxx的地址。self.xxx访问的是xxx的getter。
这两者并不是完全等价的,self.xxx是用objc_msgSend发消息,_xxx或者self->xxx则是直接访问内存地址,
一般建议在init里面用_xxx,其他地方用self.xxx,为什么呢?避免踩坑
所以用self.xxx
或者下划线_xxx
,都有很大学问。这里还可以引申至NSArray
的copy
, NSMutableArray
的strong
或一些其他类型,So 大家在写代码的时候就要注意了,代码的写法习惯真的很重要,直接影响项目的稳定性,所以大家在写代码的时候,该用什么属性就用什么属性,菜逼与大牛之间只是一线之差😎。