對(duì)象在經(jīng)歷其生命周期后,最終會(huì)為系統(tǒng)回收,這時(shí)就要執(zhí)行dealloc方法了。在每個(gè)對(duì)象的生命期內(nèi),此方法僅執(zhí)行一次,也就會(huì)說(shuō)當(dāng)保留計(jì)數(shù)降為0的時(shí)候。然而具體何時(shí)調(diào)用,則無(wú)法保證。你絕不應(yīng)該自己調(diào)用dealloc方法。運(yùn)行期系統(tǒng)會(huì)在適當(dāng)?shù)臅r(shí)候調(diào)用它。
那么應(yīng)該在dealloc方法中做些什么呢?主要就是釋放對(duì)象所擁有的引用,也就是把所有Objective-C對(duì)象都是放掉,ARC會(huì)通過(guò)自動(dòng)生成.cxx_destruce方法在dealloc中為你自動(dòng)添加這些釋放代碼。對(duì)象所擁有的其他非Objective-C對(duì)象也要釋放。
在dealloc方法中,通常還要做一件事,那就是爸原來(lái)配置過(guò)的觀測(cè)行為(observation behavior)都清理掉。如果用NSNotificationCenter給此對(duì)象訂閱(register)過(guò)某種通知,那么一般應(yīng)該在這里注銷(unregister),這樣的話,通知系統(tǒng)就不再把通知發(fā)給回收后的對(duì)象了。
雖說(shuō)應(yīng)該于dealloc中釋放引用,但是開(kāi)銷大或系統(tǒng)內(nèi)稀缺的資源則不在此列。像是文件描述(file description)、套接字(socket)、大塊內(nèi)存等,都屬于這種資源。不能指望dealloc方法必定會(huì)在某個(gè)特定的時(shí)機(jī)調(diào)用,因?yàn)橛幸恍o(wú)法預(yù)料的東西可能也持有此對(duì)象。如果非要等到系統(tǒng)調(diào)用dealloc方法時(shí)才釋放,那么保留這些稀缺資源的時(shí)間就有些過(guò)長(zhǎng)了,這么做不合適。通常的做法是,實(shí)現(xiàn)另外一個(gè)方法,當(dāng)應(yīng)用程序用完資源對(duì)象后,,就調(diào)用此方法。這樣一來(lái),資源對(duì)象的生命期就變得更為明確了。
在清理方法而非dealloc方法中清理資源還有個(gè)原因,就是系統(tǒng)并不保證每個(gè)創(chuàng)建出來(lái)的對(duì)象的dealloc都會(huì)執(zhí)行。極個(gè)別情況下,當(dāng)應(yīng)用程序終止時(shí),仍有對(duì)象處于存活狀態(tài),這些對(duì)象沒(méi)有收到dealloc消息。在Mac OS X及iOS應(yīng)用程序所對(duì)應(yīng)的application delegate中,都含有一個(gè)會(huì)于程序終止時(shí)調(diào)用的方法。如果一定要清理某些對(duì)象,那么可在此方法中調(diào)用那些對(duì)象的“清理方法”。
Mac OS X系統(tǒng)里,應(yīng)用程序終止時(shí)會(huì)調(diào)用NSApplicationDelegate之中的下列方法:
- (void)applicationWillTerminate:(NSNotification *)notification
而在iOS系統(tǒng)里,應(yīng)用程序終止時(shí)則會(huì)調(diào)用UIApplicationDelegate中的下述方法:
- (void)applicationWillTerminate:(UIApplication *)application
編寫dealloc方法時(shí)還需注意,不要在里面隨便調(diào)用其他方法。如果在這里調(diào)用的方法又要異步執(zhí)行某些任務(wù),或是又要繼續(xù)調(diào)用他們自己的某些方法,那么等到那些任務(wù)執(zhí)行完畢時(shí),系統(tǒng)已經(jīng)把當(dāng)前這個(gè)待回收的對(duì)象徹底摧毀了。
請(qǐng)?jiān)僮⒁庖粋€(gè)問(wèn)題:調(diào)用dealloc方法的那個(gè)線程會(huì)執(zhí)行“最終的釋放操作”(final release),令對(duì)象的保留計(jì)數(shù)降為0,而某些方法必須在特性的線程里(比如主線程)調(diào)用才行。若在dealloc里調(diào)用了那些方法,則無(wú)法保證當(dāng)前這個(gè)線程就是那些方法所需要的線程。
在dealloc里也不要調(diào)用屬性的存取方法,因?yàn)橛腥丝赡軙?huì)覆寫這些方法,并于其中做一些無(wú)法在回首階段安全之行的操作。此外,屬性可能正處于“鍵值觀測(cè)”(Key-Value Observation, KVO)機(jī)制的監(jiān)控之下,該屬性的觀察者(observer)可能會(huì)在屬性值改變時(shí)“保留”或使用這個(gè)即將回收的對(duì)象。
要點(diǎn)###
- 在dealloc方法里,應(yīng)該做的事情就是釋放指向其他對(duì)象的引用,并取消原來(lái)訂閱的“鍵值觀測(cè)”(KVO)或NSNotificationCenter等通知,不要做其他事情。
- 如果對(duì)象持有文件描述符等系統(tǒng)資源,那么應(yīng)該專門寫一個(gè)方法來(lái)釋放此種資源。這樣的類要和其使用者約定:用完資源后必須調(diào)用close方法。
- 執(zhí)行異步任務(wù)的方法不應(yīng)該在dealloc里調(diào)用;只能在正常狀態(tài)下執(zhí)行的那些方法也不應(yīng)在dealloc里調(diào)用,因?yàn)榇藭r(shí)對(duì)象已處于正在回收的狀態(tài)了。
文/z_zero(簡(jiǎn)書作者)原文鏈接:http://www.itdecent.cn/p/8829f7a09475著作權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),并標(biāo)注“簡(jiǎn)書作者”。