29.理解引用計數(shù)

《編寫高質(zhì)量iOS與OS X代碼的52個有效方法》--第五章 第29條
(ps:此乃讀書筆記,加深記憶,僅供大家參考)


第5章 內(nèi)存管理

ARC幾乎把所有內(nèi)存管理事宜都交給編譯器決定旧困,開發(fā)者只需專注于業(yè)務(wù)邏輯靶草。

第29條:理解引用計數(shù)

Objective-C語言使用引用計數(shù)來管理內(nèi)存,也就是說擂涛,每個對象都有個可以遞增或遞減的計數(shù)器。如果想使某個對象繼續(xù)存活聊记,那就遞增其引用計數(shù)撒妈;用完了之后,就遞減其引用計數(shù)排监。計數(shù)變?yōu)?狰右,就表示沒人關(guān)注此對象了,于是舆床,就可以把它銷毀棋蚌。

引用計數(shù)工作原理

在引用計數(shù)架構(gòu)下,對象有個計數(shù)器挨队,用以表示當(dāng)前有多少個事物想令此對象繼續(xù)存活下去附鸽。這在Objective-C中叫做“保留計數(shù)”(retain count),不過也可以叫“引用計數(shù)”(reference count)瞒瘸。NSObject協(xié)議聲明了下面三個方法用于操作計數(shù)器坷备,以遞增或遞減其值:

  • Retain 遞增保留計數(shù)。
  • release 遞減保留計數(shù)情臭。
  • autorelease 待稍后清理“自動釋放池”(autorelease pool)時省撑,再遞減保留計數(shù)。

查看保留計數(shù)的方法叫做retainCount俯在, 此方法不太有用竟秫,即便在調(diào)試時也如此,所以筆者(蘋果公司)并不推薦大家使用這個方法跷乐。

對象創(chuàng)建出來時肥败,其保留計數(shù)至少為1。 最終當(dāng)保留計數(shù)歸零時,對象就回收了(deallocated)馒稍,也就是說皿哨,系統(tǒng)會將其占用的內(nèi)存標記為“可重用”(reuse)。此時纽谒,所有指向該對象的引用也都變得無效了证膨。

對象如果持有指向其他對象的強引用(strong reference),那么前者就“擁有”(own)后者鼓黔。也就是說央勒,對象想令其所引用的那些對象繼續(xù)存活,就可將其“保留”澳化。等用完了之后崔步,再釋放。

如果按“引用樹”回溯缎谷,那么最終會發(fā)現(xiàn)一個“跟對象”(root object)井濒。在Mac OS X應(yīng)用程序中,此對象就是NSApplication對象慎陵;而在iOS應(yīng)用程序中加酵,則是UIApplication對象磷斧。兩者都是應(yīng)用程序啟動時創(chuàng)建的單例辙纬。

NSMutableArray * array = [[NSMutableArray alloc] init]; 
NSNumber * number = [[NSNumber alloc] initWithInt:2333];
[array addObject:number];    
[number release];    
//do something with 'array'    
[array release];

在Objective-C中岸蜗,調(diào)用alloc方法所返回的對象由調(diào)用者所擁有瓢颅。也就是說笛钝,調(diào)用者已通過alloc方法表達了想令該對象繼續(xù)存活下去的意思垫卤。不過請注意社牲,這并不是說此對象此時的保留計數(shù)必定是1甥厦。在alloc或“initWitInt:”方法的實現(xiàn)代碼中纺铭,也許還有其他對象也保留了此對象,所以刀疙,其保留計數(shù)至少為1舶赔。不能說保留計數(shù)一定是某個值,只能說你所執(zhí)行的操作是遞增了該計數(shù)還是遞減了該計數(shù)谦秧。

number對象調(diào)用release釋放之后竟纳,仍然存活.因為數(shù)組還在引用著它。然而絕不應(yīng)該假設(shè)此對象一定存活疚鲤,也就是說锥累,不要像下面這樣編寫代碼:

NSNumber * number = [[NSNumber alloc] initWithInt:2333];
[array addObject:number];
[number release];
NSLog(@"number = %@", number);

如果調(diào)用release由于某些原因,其保留計數(shù)降至0集歇,那么number對象所占內(nèi)存也許會回收桶略,這樣的話,在調(diào)用NSLog可能就將是程序崩潰了。這里說“可能”际歼,而沒說“一定”惶翻,因為對象所占的內(nèi)存在“解除分配”(deallocated)之后,只是放回“可用內(nèi)存池”(avaiable pool)蹬挺。如果執(zhí)行NSLog時尚未復(fù)寫對象內(nèi)存维贺,那么該對象仍然有效,這時程序不會崩潰巴帮。

為避免在不經(jīng)意間使用了無效對象溯泣,一般調(diào)用完release之后都會清空指針。這就能保證不會出現(xiàn)可能指向無效對象的指針榕茧,這種指針通常稱為“懸掛指針”(dangling pointer)垃沦。

NSNumber * number = [[NSNumber alloc] initWithInt:2333];
[array addObject:number];
[number release];
number = nil;

屬性存取方法中的內(nèi)存管理

若屬性為“strong關(guān)系”(strong relationship)用押,則設(shè)置的屬性值會保留肢簿。

- (void)setFoo:(id)foo
{
    [foo retain];
    [_foo release];
    _foo = foo;
}   

此方法將保留新值并釋放舊值,然后更新實例變量蜻拨,令其指向新值池充。順序很重要

自動釋放池

調(diào)用release會立刻遞減對象的保留計數(shù)(而且還有可能令系統(tǒng)回收此對象)缎讼,然而有時候可以不調(diào)用它收夸,改為調(diào)用autorelease,此方法會在稍后遞減計數(shù)血崭,通常是在下一次“時間循環(huán)”(event loop)時遞減卧惜,不過也可能執(zhí)行的更早些。

此特性很有用夹纫,尤其是在方法中返回對象時更應(yīng)該使用它咽瓷。在這種情況下,我們并不總是想令方法調(diào)用者手工保留其值舰讹。

- (NSString *)stringValue
{
    NSString * str = [[NSString alloc] initWithFormat:@"I am this: %@", self];
    return self;    //return [str autorelease];
}

此時返回的str對象其保留計數(shù)比期望值要多1(+1 retain count)茅姜,因為調(diào)用alloc會令保留計數(shù)加1,而又沒有與之對應(yīng)的釋放操作月匣。

這里應(yīng)該用autorelease钻洒,它會在稍后釋放對象,從而給調(diào)用者留下了足夠長的時間桶错,使其可以在需要時先保留返回值航唆。換句話說,此方法可以保證對象在跨越“方法調(diào)用邊界”(method call boundary)后一定存活院刁。

保留環(huán)

通常采用“弱引用”(weak reference)來解決此問題糯钙,或是從外界命令循環(huán)中的某個對象不再保留另一個對象。這兩種方法都能打破保留環(huán),從而避免內(nèi)存泄露任岸。

要點

  • 引用計數(shù)機制通過可以遞增遞減的計數(shù)器來管理內(nèi)存再榄。對象創(chuàng)建好之后,其保留計數(shù)至少為1享潜。若保留計數(shù)為正困鸥,則對象繼續(xù)存活。當(dāng)保留計數(shù)降為0時剑按,對象就被銷毀了疾就。
  • 在對象生命期中,其余對象通過引用來保留或釋放此對象艺蝴。保留與釋放操作分別會遞增或遞減保留計數(shù)猬腰。

理解 iOS 的內(nèi)存管理----唐巧大神

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市猜敢,隨后出現(xiàn)的幾起案子姑荷,更是在濱河造成了極大的恐慌,老刑警劉巖缩擂,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鼠冕,死亡現(xiàn)場離奇詭異,居然都是意外死亡胯盯,警方通過查閱死者的電腦和手機懈费,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陨闹,“玉大人楞捂,你說我怎么就攤上這事薄坏∏骼鳎” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵胶坠,是天一觀的道長君账。 經(jīng)常有香客問我,道長沈善,這世上最難降的妖魔是什么乡数? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮闻牡,結(jié)果婚禮上净赴,老公的妹妹穿的比我還像新娘。我一直安慰自己罩润,他們只是感情好玖翅,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般金度。 火紅的嫁衣襯著肌膚如雪应媚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天猜极,我揣著相機與錄音中姜,去河邊找鬼。 笑死跟伏,一個胖子當(dāng)著我的面吹牛丢胚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播受扳,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嗜桌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辞色?” 一聲冷哼從身側(cè)響起骨宠,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎相满,沒想到半個月后层亿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡立美,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年匿又,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片建蹄。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡碌更,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出洞慎,到底是詐尸還是另有隱情痛单,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布劲腿,位于F島的核電站旭绒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏焦人。R本人自食惡果不足惜挥吵,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望花椭。 院中可真熱鬧忽匈,春花似錦、人聲如沸矿辽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嫌松,卻和暖如春沪曙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背萎羔。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工液走, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贾陷。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓缘眶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親髓废。 傳聞我的和親對象是個殘疾皇子巷懈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

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