NSString的類型、存儲位置

先來看一個例子:

#if __has_feature(objc_arc)
#define Obj_RetainCount(obj) CFGetRetainCount((__bridge CFTypeRef)(obj))
#else
#define Obj_RetainCount(obj) DebugLog(@"%lu",[obj retainCount]);
#endif

#define HFLog(_var) \
NSLog(@"%@ : class = %@ p = %p retainCount = %ld",@#_var,NSStringFromClass([_var class]),_var,\
(unsigned long)Obj_RetainCount(_var));


    NSString *a = @"str";
    NSString *b = [[NSString alloc] init];
    NSString *c = [[NSString alloc] initWithString:@"str"];
    
    NSString *d = [[NSString alloc] initWithFormat:@"<10"];
    NSString *e = [NSString stringWithFormat:@"<10"];
    NSString *f = [d copy];    
    NSString *g = [a copy];
    
    NSString *h = [[NSString alloc] initWithFormat:@"1234567890"];
    NSString *i = [NSString stringWithFormat:@"1234567890"];

    NSMutableString *mString1 = [NSMutableString stringWithString:@"<10"];
    NSMutableString *mString2 = [NSMutableString stringWithFormat:@"<10"];
    NSMutableString *mString3 = [[NSMutableString alloc] initWithFormat:@"1234567890"];

    HFLog(a);
    HFLog(b);
    HFLog(c);
    HFLog(d);
    HFLog(e);
    HFLog(f);
    HFLog(g);
    HFLog(h);
    HFLog(i)
    HFLog(mString1);
    HFLog(mString2);
    HFLog(mString3);

輸出結(jié)果為:
<pre>
a : class = __NSCFConstantString p = 0x107105b00 retainCount = 1152921504606846975
b : class = __NSCFConstantString p = 0x107f62178 retainCount = 1152921504606846975
c : class = __NSCFConstantString p = 0x107105b00 retainCount = 1152921504606846975
d : class = NSTaggedPointerString p = 0xebeeae3f52cf0333 retainCount = 9223372036854775807
e : class = NSTaggedPointerString p = 0xebeeae3f52cf0333 retainCount = 9223372036854775807
f : class = NSTaggedPointerString p = 0xebeeae3f52cf0333 retainCount = 9223372036854775807
g : class = NSTaggedPointerString p = 0xebeeae3f52cf0333 retainCount = 9223372036854775807
h : class = __NSCFString p = 0x60000168f3c0 retainCount = 1
i : class = __NSCFString p = 0x60000168f3e0 retainCount = 2
mString1 : class = __NSCFString p = 0x60000310cb70 retainCount = 1
mString2 : class = __NSCFString p = 0x60000310d260 retainCount = 2
mString3 : class = __NSCFString p = 0x60000310d140 retainCount = 1
</pre>

可以看到没卸,不同方式創(chuàng)建的字符串類型不同泥技,引用計數(shù)也有所區(qū)別伦连,并不是我們常規(guī)理解的對象初始化后引用計數(shù)為1酵使。創(chuàng)建的字符串有3種類型

  • __NSCFConstantString
  • __NSCFString
  • __NSTaggedPointerString

造成這種結(jié)果的原因是由于OC對字符串做的內(nèi)存優(yōu)化。

__NSCFConstantString

對變量類型名上就可以看出对省,這種類型的字符串是常量字符串蝗拿。該類型的字符串以字面量的方式創(chuàng)建,保存在字符串常量區(qū)蒿涎,是在編譯時創(chuàng)建的哀托。如上a,b,c,打印結(jié)果:

<pre>
class = __NSCFConstantString p = 0x107105b00 retainCount = 1152921504606846975
</pre>

對于 initWithString 實例方法以及 stringWithString 類方法,編譯器會給出redundant警告,原因是該方法創(chuàng)建字符串等同于直接復(fù)制字符串字面量.
當創(chuàng)建的字符串變量值在常量區(qū)已經(jīng)存在時劳秋,會指向那個字符串,這是編譯器做的優(yōu)化仓手。
由于是常量,因此其內(nèi)存管理并不同于對象的內(nèi)存管理玻淑,引用計數(shù)用整形格式打出來始終為-1嗽冒。(此處1152921504606846975打印為%ld,對象的引用計數(shù)是64位OS下無符號長整型的最大值补履,后面不做解釋)添坊。

__NSCFString

__NSCFString 表示對象類型的字符串,在運行時創(chuàng)建箫锤,保存在堆區(qū)贬蛙,初始引用計數(shù)為1雨女,其內(nèi)存管理方式就是對象的內(nèi)存管理方式。該種類型字符串通過format方式創(chuàng)建阳准,并且字符串內(nèi)容僅由數(shù)字氛堕、字母和常規(guī)ASCII字符構(gòu)成,且其長度>=10溺职,否則創(chuàng)建的是NSTaggedPointerString類型岔擂。

如上h,i打印結(jié)果:
<pre>
h : class = __NSCFString p = 0x600003f33580 retainCount = 2
i : class = __NSCFString p = 0x600003f32800 retainCount = 1
</pre>
可見當以format創(chuàng)建出來的字符串>9個時,會創(chuàng)建NSCFString類型浪耘,引用計數(shù)從1開始計算。
此處

個人的理解:format后面的字符串>9創(chuàng)建在堆上塑崖,引用計數(shù)初始為1七冲,stringWith是對該字符串的引用,因此i的retainCount = 2规婆,而h新獲得的字符串是alloc init,重新開辟的內(nèi)存澜躺,所以retainCount = 1。

NSTaggedPointerString

NSTaggedPointerString 類型的字符串是對__NSCFString類型的一種優(yōu)化抒蚜,在運行時創(chuàng)建字符串時掘鄙,會對字符串內(nèi)容及長度作判斷,若內(nèi)容由ASCII字符構(gòu)成且長度<10嗡髓,這時候創(chuàng)建的字符串類型就是 NSTaggedPointerString (標簽指針字符串)操漠,字符串直接存儲在指針的內(nèi)容中。NSTaggedPointerString 類型的字符串引用計數(shù)同樣為-1饿这,不適用對象的內(nèi)存管理策略浊伙。

<pre>
class = NSTaggedPointerString p = 0xebeeae3f52cf0333 retainCount = 9223372036854775807
</pre>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市长捧,隨后出現(xiàn)的幾起案子嚣鄙,更是在濱河造成了極大的恐慌,老刑警劉巖串结,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哑子,死亡現(xiàn)場離奇詭異,居然都是意外死亡肌割,警方通過查閱死者的電腦和手機卧蜓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來声功,“玉大人烦却,你說我怎么就攤上這事∠劝停” “怎么了其爵?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵冒冬,是天一觀的道長。 經(jīng)常有香客問我摩渺,道長简烤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任摇幻,我火速辦了婚禮横侦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绰姻。我一直安慰自己枉侧,他們只是感情好,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布狂芋。 她就那樣靜靜地躺著榨馁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帜矾。 梳的紋絲不亂的頭發(fā)上翼虫,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機與錄音屡萤,去河邊找鬼珍剑。 笑死,一個胖子當著我的面吹牛死陆,可吹牛的內(nèi)容都是我干的招拙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼翔曲,長吁一口氣:“原來是場噩夢啊……” “哼迫像!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瞳遍,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤闻妓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掠械,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體由缆,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年猾蒂,在試婚紗的時候發(fā)現(xiàn)自己被綠了均唉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肚菠。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡层扶,死狀恐怖檬寂,靈堂內(nèi)的尸體忽然破棺而出桶至,到底是詐尸還是另有隱情,我是刑警寧澤野瘦,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布吏廉,位于F島的核電站史辙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏耙蔑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一疯汁、第九天 我趴在偏房一處隱蔽的房頂上張望谤碳。 院中可真熱鬧塑煎,春花似錦、人聲如沸冷尉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雀哨。三九已至,卻和暖如春私爷,著一層夾襖步出監(jiān)牢的瞬間雾棺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工衬浑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捌浩,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓工秩,卻偏偏與公主長得像尸饺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子助币,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

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