iOS NSString copy 与 strong 误区指引

今天对 NSString copystrong属性进行一次在ARC模式下的详解,与MRC模式下,主要是retain 引用计数的问题 (+1,不+1,加多少个1,跟你没有半毛钱的关系,😆此处废话,忽略)。
copy属性的意思就是复制一份给自己,strong属性就是强引用。很好理解,我们先来看看效果。

@property (nonatomic,copy) NSString *c_String;

@property (nonatomic,strong) NSString *s_String;

定义一个可变的字符串tempString,分别对c_Strings_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

如果在这样子的一个情况下,copystrong属性并不会有什么分别,所以有时候我们把字符串定义成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,都有很大学问。这里还可以引申至NSArraycopyNSMutableArraystrong 或一些其他类型,So 大家在写代码的时候就要注意了,代码的写法习惯真的很重要,直接影响项目的稳定性,所以大家在写代码的时候,该用什么属性就用什么属性,菜逼与大牛之间只是一线之差😎。

嗯!今天就到这里,下期再见👋

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容