iOS NSString詳細(xì)用法

一往弓、NSString的內(nèi)存管理機(jī)制

1植锉、眾所周知,在Objective-C中的內(nèi)存管理是通過(guò)一種叫做“引用計(jì)數(shù)器”的機(jī)制管理的簇宽。舉例勋篓, 當(dāng)我們聲明了一個(gè)新的實(shí)例:
NSData *data = [[NSData alloc] init];
NSLog(@"%ld",[data retainCount]);//打印輸出為1

如果我們?cè)俅我盟臅r(shí)候,他的引用計(jì)數(shù)值會(huì)+1變?yōu)?魏割。使用完畢后需要調(diào)用[data release] ,使引用計(jì)數(shù)-1. 當(dāng)該值為零的時(shí)候譬嚣,系統(tǒng)會(huì)將data實(shí)例回收掉并釋放內(nèi)存。

[data release];
2钞它、請(qǐng)問(wèn)在這種情況下會(huì)不會(huì)造成內(nèi)存泄露拜银?為什么不會(huì)崩潰?

代碼如下:

NSString *str = [[NSString alloc] initWithString:@"ABC"];
str = @"123";
[str release];
NSLog(@"%@".str);
(1)首先遭垛,咱們先對(duì)這段代碼進(jìn)行分析尼桶。
  • 第一句 聲明了一個(gè)NSString類型的實(shí)例 str, 并將其初始化init后賦值為@"ABC"
  • 第二行锯仪,將str的指針指向了一個(gè)常量@"123"泵督。 理論上講在第一行初始化的@"ABC"沒(méi)有任何任何指針指向了。 所以造成了內(nèi)存泄露
  • 然后第三行庶喜, 將str的引用計(jì)數(shù)-1
  • 第四行輸出str的值 為123.
(2)然后回答為什么不會(huì)崩潰小腊, 因?yàn)榈谌械膔elease 實(shí)際上是release了一個(gè)常量@"123" 而作為常量,其默認(rèn)的引用計(jì)數(shù)值是很大的(100k+)溃卡,不信的話你們可以試試這句:
NSLog(@"retainCount = %d",[@"123" retainCount]);
(3)最終的輸出值會(huì)是一個(gè)很大很大的數(shù)溢豆。 所以單單一個(gè)release是不會(huì)將其釋放掉的。
(4)最后再回答這樣會(huì)不會(huì)造成內(nèi)存泄露瘸羡。理論上是會(huì)內(nèi)存泄漏的。

但是實(shí)際上搓茬,Objective-C對(duì)NSString類型有特殊照顧犹赖。所有的NSString的引用計(jì)數(shù)器默認(rèn)初始值都會(huì)非常非常大。
NSString是一個(gè)不可變的字符串對(duì)象卷仑。這不是表示這個(gè)對(duì)象聲明的變量的值不可變峻村,而是表示它初始化以后,你不能改變?cè)撟兞克峙涞膬?nèi)存中的值锡凝,但你可以重新分配該變量所處的內(nèi)存空間粘昨。

二、__NSCFConstantString的解釋

那么__NSCFConstantString是什么呢窜锯?其實(shí)__NSCFConstantString是一個(gè)字符串常量张肾,是沒(méi)有retainCount(引用計(jì)數(shù))的,所以沒(méi)有強(qiáng)指針指向它锚扎,它也不會(huì)被銷毀吞瞪。那么,怎么獲得不是__NSCFConstantString的字符串呢驾孔?

NSString *string1 = @"string 1";  
NSString *string2 = [NSString stringWithString:@"string 2"];  
NSString *string3 = [NSString stringWithFormat:@"string 3"];  
NSString *string4 = [[NSString alloc] initWithString:@"string 4"];  
NSString *string5 = [[NSMutableString alloc] initWithString:@"string"];  
NSLog(@"%@:%@",string1,[string1 class]);  
NSLog(@"%@:%@",string2,[string2 class]);  
NSLog(@"%@:%@",string3,[string3 class]);  
NSLog(@"%@:%@",string4,[string4 class]);  
NSLog(@"%@:%@",string5,[string5 class]); 
運(yùn)行結(jié)果:
2015-04-18 10:14:35.587 內(nèi)存管理[6631:201537] string 1:__NSCFConstantString
2015-04-18 10:14:35.587 內(nèi)存管理[6631:201537] string 2:__NSCFConstantString
2015-04-18 10:14:35.587 內(nèi)存管理[6631:201537] string 3:NSTaggedPointerString
2015-04-18 10:14:35.587 內(nèi)存管理[6631:201537] string 4:__NSCFConstantString
2015-04-18 10:14:35.588 內(nèi)存管理[6631:201537] string5:__NSCFString
通過(guò)以上的運(yùn)行結(jié)果芍秆,發(fā)現(xiàn)只有使用[[NSMutableString alloc] initWithString:]得到的NSString才是__NSCFString惯疙。

三、NSString特性分析學(xué)習(xí)

我們都知道NSString是一個(gè)Objective-C的類妖啥,但是我們有時(shí)發(fā)現(xiàn)它的對(duì)象在內(nèi)存管理上貌似和其他的對(duì)象有一些區(qū)別霉颠。比如有時(shí)你會(huì)發(fā)現(xiàn)對(duì)一個(gè)NSString進(jìn)行copy操作時(shí),它還是原本的對(duì)象荆虱,實(shí)際上并未拷貝對(duì)象蒿偎。本博客就來(lái)研究下這個(gè)問(wèn)題。

1.NSString內(nèi)存管理特性分析
1.1 準(zhǔn)備

為了方便測(cè)試克伊,我先寫了個(gè)宏酥郭,用來(lái)打印NSString的isa、內(nèi)存地址愿吹、值不从、retainCount。 注:為了了解內(nèi)存特性犁跪,后面的代碼都使用了手動(dòng)內(nèi)存管理椿息。

#define TLog(_var) ({ NSString *name = @#_var; NSLog(@"%@: %@ -> %p : %@  %d", name, [_var class], _var, _var, (int)[_var retainCount]); })
1.2 NSString的創(chuàng)建
1.2.1測(cè)試NSString

在objc中,我們一般通過(guò)幾種方法來(lái)創(chuàng)建NSString呢坷衍,一般有三種方法寝优,現(xiàn)在我們就分別對(duì)這三種情況寫段測(cè)試代碼,如下:

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

看到上面這段測(cè)試代碼枫耳,我們可以發(fā)現(xiàn)幾點(diǎn)同我們想象不同的地方:

  • 第一種方式和第二種方式創(chuàng)建出來(lái)的NSString時(shí)一模一樣的乏矾,isa是__NSCFConstantString,內(nèi)存地址一樣迁杨,retainCount是-1.
  • 第三種方式創(chuàng)建的NSString和創(chuàng)建其他objc對(duì)象類似的钻心,在堆上分配內(nèi)存,初始retainCount為1.
    這里面有幾個(gè)疑問(wèn):
  • 什么是__NSCFConstantString铅协?
  • 為什么第一種和第二種NSString的內(nèi)存地址是一樣的捷沸?
  • 為什么他們的retainCount是-1?
1.2.2 NSString創(chuàng)建的寫法

其實(shí)上面第一種寫法和第二種寫法是完全一樣的狐史,沒(méi)有任何區(qū)別痒给,從iosSDK6開(kāi)始,第二種寫法已經(jīng)被遺棄了骏全,如果用第二種寫法創(chuàng)建NSString,編譯器就會(huì)報(bào)一個(gè)警告苍柏。

1.2.3 retainCount為-1是什么情況

1、首先retainCount是NSUInteger的類型吟温,其實(shí)上面的打印是將它作為int類型打印序仙。所以它其實(shí)不是-1,它的實(shí)際值是4294967295鲁豪。
2潘悼、在objc的retainCount中.如果對(duì)象的retainCount為這個(gè)值律秃,就意味著“無(wú)限的retainCount”,這個(gè)對(duì)象是不能被釋放的治唤。
3棒动、所有的 __NSCFConstantString對(duì)象的retainCount都為-1,這就意味著 __NSCFConstantString不會(huì)被釋放宾添,使用第一種方法創(chuàng)建的NSString船惨,如果值一樣,無(wú)論寫多少遍缕陕,都是同一個(gè)對(duì)象粱锐。而且這種對(duì)象可以直接用 == 來(lái)比較

NSString *str1 = @"1234567890";    TLog(str1);
//str1: __NSCFConstantString -> 0x715ec : 1234567890  -1
NSString *str2 = @"1234567890";    TLog(str2);
//str2: __NSCFConstantString -> 0x715ec : 1234567890  -1
assert(@"abc"==@"abc"); //一直正確
1.3 NSString的retain、copy和mutableCopy

我們寫一段代碼分別對(duì) __NSCFConstantString 和 __NSCFString 進(jìn)行retain和copy測(cè)試

NSString *str1 = @"a";    TLog(str1);
NSString *str2 = [str1 retain];  TLog(str2);
NSString *str3 = [str1 copy]; TLog(str3);
NSString *str4 = [str1 mutableCopy]; TLog(str4);

/*
 str1: __NSCFConstantString -> 0x7c5e0 : a  -1
 str2: __NSCFConstantString -> 0x7c5e0 : a  -1
 str3: __NSCFConstantString -> 0x7c5e0 : a  -1
 str4: __NSCFString -> 0x1559eb80 : a  1
*/

上面的測(cè)試可以看出扛邑,對(duì)一個(gè)__NSCFConstantString進(jìn)行retain和copy操作都還是自己怜浅,沒(méi)有任何變化,對(duì)其mutableCopy操作可將其拷貝到堆上蔬崩,retainCount為1.

NSString *str1 = [@"a" mutableCopy];    TLog(str1);
NSString *str2 = [str1 retain];  TLog(str2);
NSString *str3 = [str1 copy]; TLog(str3);
NSString *str4 = [str1 mutableCopy]; TLog(str4);

/*
str1: __NSCFString -> 0x17d6d280 : a  1
str2: __NSCFString -> 0x17d6d280 : a  2
str3: __NSCFConstantString -> 0x3bd40090 : a  -1
str4: __NSCFString -> 0x17e684d0 : a  1
*/

上面的測(cè)試中恶座,我們發(fā)現(xiàn),對(duì)__NSCFString進(jìn)行retain和mutableCopy操作時(shí)沥阳,其特性符合正常的對(duì)象特性跨琳。但是對(duì)其copy時(shí),它卻變成了一個(gè)__NSCFConstantString對(duì)象桐罕!為了確定什么情況下才會(huì)出現(xiàn)這種現(xiàn)象我們多做一些測(cè)試

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

2. 小結(jié)

經(jīng)過(guò)這一系列的測(cè)試分析脉让,讓我們認(rèn)識(shí)了__NSCFConstantString以及它的一些特性,它是在編譯時(shí)就決定的功炮,不能在運(yùn)行時(shí)創(chuàng)建侠鳄。

3. NSString屬性什么時(shí)候用copy,什么時(shí)候用strong?

http://southpeak.github.io/2015/05/10/ios-techset-1/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末死宣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子碴开,更是在濱河造成了極大的恐慌毅该,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件潦牛,死亡現(xiàn)場(chǎng)離奇詭異眶掌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)巴碗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門朴爬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人橡淆,你說(shuō)我怎么就攤上這事召噩∧刚裕” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵具滴,是天一觀的道長(zhǎng)凹嘲。 經(jīng)常有香客問(wèn)我,道長(zhǎng)构韵,這世上最難降的妖魔是什么周蹭? 我笑而不...
    開(kāi)封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮疲恢,結(jié)果婚禮上凶朗,老公的妹妹穿的比我還像新娘。我一直安慰自己显拳,他們只是感情好棚愤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著萎攒,像睡著了一般遇八。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耍休,一...
    開(kāi)封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天刃永,我揣著相機(jī)與錄音,去河邊找鬼羊精。 笑死斯够,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喧锦。 我是一名探鬼主播读规,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼燃少!你這毒婦竟也來(lái)了束亏?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤阵具,失蹤者是張志新(化名)和其女友劉穎碍遍,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體阳液,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怕敬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帘皿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片东跪。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出虽填,到底是詐尸還是另有隱情丁恭,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布卤唉,位于F島的核電站涩惑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏桑驱。R本人自食惡果不足惜竭恬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望熬的。 院中可真熱鬧痊硕,春花似錦、人聲如沸押框。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)橡伞。三九已至盒揉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兑徘,已是汗流浹背刚盈。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挂脑,地道東北人藕漱。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像崭闲,于是被迫代替她去往敵國(guó)和親肋联。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,130評(píng)論 30 470
  • 1.項(xiàng)目經(jīng)驗(yàn) 2.基礎(chǔ)問(wèn)題 3.指南認(rèn)識(shí) 4.解決思路 ios開(kāi)發(fā)三大塊: 1.Oc基礎(chǔ) 2.CocoaTouch...
    陽(yáng)光的大男孩兒閱讀 4,971評(píng)論 0 13
  • iOS面試題及答案 1. Object-c的類可以多重繼承么?可以實(shí)現(xiàn)多個(gè)接口么?Category是什么?重寫一...
    iOS_阿輝閱讀 1,907評(píng)論 0 32
  • 最近一朋友正準(zhǔn)備跳槽刁俭,就從各處搜索整理一些基礎(chǔ)橄仍,便于朋友復(fù)習(xí),也便于自己復(fù)習(xí)查看. 1. 回答person的ret...
    smile麗語(yǔ)閱讀 1,727評(píng)論 0 7
  • 內(nèi)存管理 簡(jiǎn)述OC中內(nèi)存管理機(jī)制牍戚。與retain配對(duì)使用的方法是dealloc還是release沙兰,為什么?需要與a...
    丶逐漸閱讀 1,950評(píng)論 1 16