NSString 何时使用strong,何时使用copy

对于NSString 何时使用strong,何时使用copy,首页让我们来具体的了解一下NSString的一些内部特性,下面一篇文章总结的非常好:

NSString特性分析学习

我们都知道NSString是一个Objective-C的类,但是我们有时发现它的对象在内存管理上貌似和其他的对象有一些区别。比如有时你会发现对一个NSString进行copy操作时,它还是原本的对象,实际上并未拷贝对象。本博客就来研究下这个问题。

1.NSString内存管理特性分析

1.1 准备

为了方便测试,我先写了个宏,用来打印NSString的isa、内存地址、值、retainCount。注:为了了解内存特性,后面的代码都使用了手动内存管理。

#define TLog(_var) ({ NSString *name = @#_var; NSLog(@"%@: %@ -> %p : %@  %d", name, [_var class], _var, _var, (int)[_var retainCount]); })

1.2 NSString的创建

1.2.1测试NSString

在objc中,我们一般通过几种方法来创建NSString呢,一般有三种方法,现在我们就分别对这三种情况写段测试代码,如下:

12345678

NSString*str1=@"1234567890";TLog(str1);//str1: __NSCFConstantString -> 0x715ec : 1234567890  -1NSString*str2=[NSStringstringWithString:@"1234567890"];TLog(str2);//str2: __NSCFConstantString -> 0x715ec : 1234567890  -1NSString*str3=[NSStringstringWithFormat:@"1234567890"];TLog(str3);//str3: __NSCFString -> 0x1557cb50 : 1234567890  1

看到上面这段测试代码,我们可以发现几点同我们想象不同的地方:

第一种方式和第二种方式创建出来的NSString时一模一样的,isa是__NSCFConstantString,内存地址一样,retainCount是-1.

第三种方式创建的NSString和创建其他objc对象类似的,在堆上分配内存,初始retainCount为1.

这里面有几个疑问:

什么是__NSCFConstantString?

为什么第一种和第二种NSString的内存地址是一样的?

为什么他们的retainCount是-1?

1.2.2 NSString创建的写法

其实上面第一种写法和第二种写法是完全一样的,没有任何区别,从iosSDK6开始,第二种写法已经被遗弃了,如果用第二种写法创建NSString,编译器就会报一个警告。

1.2.3 retainCount为-1是什么情况

首先retainCount是NSUInteger的类型,其实上面的打印是将它作为int类型打印。所以它其实不是-1,它的实际值是4294967295。

在objc的retainCount中.如果对象的retainCount为这个值,就意味着“无限的retainCount”,这个对象是不能被释放的。

所有的 __NSCFConstantString对象的retainCount都为-1,这就意味着 __NSCFConstantString不会被释放,使用第一种方法创建的NSString,如果值一样,无论写多少遍,都是同一个对象。而且这种对象可以直接用==来比较

1234567

NSString*str1=@"1234567890";TLog(str1);//str1: __NSCFConstantString -> 0x715ec : 1234567890  -1NSString*str2=@"1234567890";TLog(str2);//str2: __NSCFConstantString -> 0x715ec : 1234567890  -1assert(@"abc"==@"abc");//一直正确

1.3 NSString的retain、copy和mutableCopy

我们写一段代码分别对 __NSCFConstantString 和 __NSCFString 进行retain和copy测试

__NSCFConstantString

1234567891011

NSString*str1=@"a";TLog(str1);NSString*str2=[str1retain];TLog(str2);NSString*str3=[str1copy];TLog(str3);NSString*str4=[str1mutableCopy];TLog(str4);/*str1: __NSCFConstantString -> 0x7c5e0 : a  -1str2: __NSCFConstantString -> 0x7c5e0 : a  -1str3: __NSCFConstantString -> 0x7c5e0 : a  -1str4: __NSCFString -> 0x1559eb80 : a  1*/

上面的测试可以看出,对一个__NSCFConstantString进行retain和copy操作都还是自己,没有任何变化,对其mutableCopy操作可将其拷贝到堆上,retainCount为1.

__NSCFString

1234567891011

NSString*str1=[@"a"mutableCopy];TLog(str1);NSString*str2=[str1retain];TLog(str2);NSString*str3=[str1copy];TLog(str3);NSString*str4=[str1mutableCopy];TLog(str4);/*str1: __NSCFString -> 0x17d6d280 : a  1str2: __NSCFString -> 0x17d6d280 : a  2str3: __NSCFConstantString -> 0x3bd40090 : a  -1str4: __NSCFString -> 0x17e684d0 : a  1*/

上面的测试中,我们发现,对__NSCFString进行retain和mutableCopy操作时,其特性符合正常的对象特性。但是对其copy时,它却变成了一个__NSCFConstantString对象!为了确定什么情况下才会出现这种现象我们多做一些测试

12345678910111213141516171819202122232425262728

NSString*str1=[[@"a"mutableCopy]copy];TLog(str1);NSString*str2=[NSStringstringWithFormat:@"%s","a"];TLog(str2);NSString*str3=[[[@"path/a"lastPathComponent]mutableCopy]copy];TLog(str3);NSString*str4=[[@"b"mutableCopy]copy];TLog(str4);NSString*str5=[[@"c"mutableCopy]copy];TLog(str5);NSString*str6=[[@"d"mutableCopy]copy];TLog(str6);NSString*str7=[[@"e"mutableCopy]copy];TLog(str7);NSString*str8=[[@"f"mutableCopy]copy];TLog(str8);NSString*str9=[[@"\\"mutableCopy]copy];TLog(str9);NSString*str10=[[@"$"mutableCopy]copy];TLog(str10);NSString*str11=[[@"."mutableCopy]copy];TLog(str11);NSString*str12=[[@"aa"mutableCopy]copy];TLog(str12);/*str1: __NSCFConstantString -> 0x3bd40090 : a  -1str2: __NSCFConstantString -> 0x3bd40090 : a  -1str3: __NSCFConstantString -> 0x3bd40090 : a  -1str4: __NSCFString -> 0x175ab390 : b  1str5: __NSCFString -> 0x176a5ce0 : c  1str6: __NSCFString -> 0x175ab960 : d  1str7: __NSCFString -> 0x176a5cc0 : e  1str8: __NSCFString -> 0x176a5d50 : f  1str9: __NSCFString -> 0x176a5d60 : \  1str10: __NSCFString -> 0x176a6700 : $  1str11: __NSCFString -> 0x175ab750 : .  1str12: __NSCFString -> 0x175ab760 : aa  1*/

起初我以为是ASCII字符比较特殊,经过上面这一段的测试发现,只有@“a”才有这样的现象,我又用模拟器测试了这一段代码,结果得到的都是_NSTaggedPointerString的对象。Tagged Pointer是一个能够提升性能、节省内存的有趣的技术。在OS X 10.10中,NSString就采用了这项技术,具体可参考这篇博客:http://blog.csdn.net/demondev/article/details/50396815

因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.

如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.

copy 此特质所表达的所属关系与 strong 类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。当属性类型为 NSString 时,经常用此特质来保护其封装性。因为传递给设置方法的新值有可能指向一个 NSMutableString 类的实例。这个类是 NSString 的子类,表示一种可修改其值的字符串。此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。

Copy-MutableCopy.png

拷贝

实现拷贝的方法有2个

copy:返回不可变副本

mutableCopy:返回可变副本

普通对象实现拷贝的步骤

遵守协议

实现-copyWithZone:方法

创建新对象

给新对象的属性赋值

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

推荐阅读更多精彩内容