iOS 開發(fā)刷題系列三:NSString 引用計(jì)數(shù)

下面的程序會(huì)輸出什么狮鸭?

    NSMutableArray *ary = [[NSMutableArray array] retain];
    NSString *str = [NSString stringWithFormat:@"123456789"];
    NSString *longStr = [NSString stringWithFormat:@"1234567890"];
    
    [str retain];
    [longStr retain];
    [ary addObject:str];
    [ary addObject:longStr];
    
    NSLog(@"str = %ld", (unsigned long)[str retainCount]);
    NSLog(@"longStr = %ld", (unsigned long)[longStr retainCount]);
    
    [str retain];
    [str release];
    [str release];
    [longStr retain];
    [longStr release];
    [longStr release];
    
    NSLog(@"str = %ld", (unsigned long)[str retainCount]);
    NSLog(@"longStr = %ld", (unsigned long)[longStr retainCount]);
    [ary removeAllObjects];
    NSLog(@"str = %ld", (unsigned long)[str retainCount]);
    NSLog(@"longStr = %ld", (unsigned long)[longStr retainCount]);

輸出結(jié)果

2018-07-03 13:54:59.951143+0800 BlockTestDemo[13502:2107264] str = -1
2018-07-03 13:54:59.951374+0800 BlockTestDemo[13502:2107264] longStr = 3
2018-07-03 13:54:59.951613+0800 BlockTestDemo[13502:2107264] str = -1
2018-07-03 13:54:59.951717+0800 BlockTestDemo[13502:2107264] longStr = 2
2018-07-03 13:54:59.951956+0800 BlockTestDemo[13502:2107264] str = -1
2018-07-03 13:54:59.952044+0800 BlockTestDemo[13502:2107264] longStr = 1

在網(wǎng)上搜索了一下合搅,一般人給出的答案是:當(dāng)字符串長(zhǎng)度小于10時(shí),字符串是保存在常量區(qū)歧蕉,沒有引用計(jì)數(shù)灾部。如果長(zhǎng)度大于等于10呢,就會(huì)被復(fù)制到堆去惯退,有引用計(jì)數(shù)赌髓。

后來又出現(xiàn)了一個(gè)詞:Tagged Pointer 具體了解一下。 嘗試著輸出字符串的class催跪,發(fā)現(xiàn)兩者的類名是不同的:

NSString *str = [NSString stringWithFormat:@"123456789"];
NSString *longStr = [NSString stringWithFormat:@"1234567890"];
NSLog(@"str %s %p", object_getClassName(str), str);
NSLog(@"longStr %s %p", object_getClassName(longStr), longStr);
2018-07-03 13:54:59.950804+0800 BlockTestDemo[13502:2107264] str NSTaggedPointerString 0xa1ea1f72bb30ab19
2018-07-03 13:54:59.950979+0800 BlockTestDemo[13502:2107264] longStr __NSCFString 0x60c000224f20

Tagged Pointer專門用來存儲(chǔ)小的對(duì)象锁蠕,例如NSNumber和NSDate
Tagged Pointer指針的值不再是地址了,而是真正的值懊蒸。所以荣倾,實(shí)際上它不再是一個(gè)對(duì)象了,它只是一個(gè)披著對(duì)象皮的普通變量而已骑丸。所以舌仍,它的內(nèi)存并不存儲(chǔ)在堆中,也不需要malloc和free通危。

這應(yīng)該也是上面的NSString在長(zhǎng)度小于10的時(shí)候铸豁,沒有引用計(jì)數(shù)的原因了。

引申

這種情況引申出另外一道題:

@property (nonatomic, strong) NSString *strongStr;

dispatch_queue_t queue = dispatch_queue_create("strongStr", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 100000; i++) {
        dispatch_async(queue, ^{
            self.strongStr = [NSString stringWithFormat:@"ab %d", i];
        });
    }

如果將dispatch_async 里面的內(nèi)容改成:

self.strongStr = [NSString stringWithFormat:@"abcdefghijklmn %d", i];

會(huì)如何菊碟?
前者不會(huì)crash, 而后者會(huì)crash节芥。
我們來看一下strongStr的setter方法:

- (void)setStrongStr:(NSString *)strongStr {
    if (strongStr == _strongStr) return;
    id pre = _strongStr;
    [strongStr retain];//1.先保留新值
    _strongStr = strongStr;//2.再進(jìn)行賦值
    [pre release];//3.釋放舊值
}

結(jié)合上面的Tagged Pointer的解釋,調(diào)用retain or release時(shí)strongStr的引用計(jì)數(shù)一直都是-1;
而對(duì)于后者逆害,strongStr實(shí)際上是一個(gè)對(duì)象头镊,retain會(huì)使引用計(jì)數(shù)+1,release會(huì)使引用計(jì)數(shù) -1;
而對(duì)于多線程異步并行執(zhí)行setStrongStr方法魄幕,可能會(huì)出現(xiàn)這種情況:多個(gè)線程拿到同一個(gè)舊值拧晕,然后給strongStr賦值不同的新值,然后在對(duì)舊值的release時(shí)候梅垄,出現(xiàn)多次release厂捞,程序crash;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市队丝,隨后出現(xiàn)的幾起案子靡馁,更是在濱河造成了極大的恐慌,老刑警劉巖机久,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件臭墨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡膘盖,警方通過查閱死者的電腦和手機(jī)胧弛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門尤误,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人结缚,你說我怎么就攤上這事损晤。” “怎么了红竭?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵尤勋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我茵宪,道長(zhǎng)最冰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任稀火,我火速辦了婚禮暖哨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凰狞。我一直安慰自己篇裁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布服球。 她就那樣靜靜地躺著,像睡著了一般颠焦。 火紅的嫁衣襯著肌膚如雪斩熊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天伐庭,我揣著相機(jī)與錄音粉渠,去河邊找鬼。 笑死圾另,一個(gè)胖子當(dāng)著我的面吹牛霸株,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播集乔,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼去件,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了扰路?” 一聲冷哼從身側(cè)響起尤溜,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎汗唱,沒想到半個(gè)月后宫莱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哩罪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年授霸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了巡验。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碘耳,死狀恐怖显设,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情藏畅,我是刑警寧澤敷硅,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站愉阎,受9級(jí)特大地震影響绞蹦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜榜旦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一幽七、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溅呢,春花似錦澡屡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至铣墨,卻和暖如春室埋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伊约。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工姚淆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屡律。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓腌逢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親超埋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子搏讶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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