官方給出的dealloc
翻譯
外部在什么情況下會(huì)觸發(fā)dealloc方法?
- 當(dāng)一個(gè)對(duì)象retain count為0 (不再有強(qiáng)引用指向)時(shí)會(huì)觸發(fā)dealloc。
注意直接把nil賦值給一個(gè)對(duì)象,不代表一定會(huì)觸發(fā)dealloc。
dealloc 內(nèi)部實(shí)現(xiàn)方法的調(diào)用時(shí)機(jī)又是 什么?
如果開(kāi)發(fā)者實(shí)現(xiàn)了dealloc方法,那么先執(zhí)行dealloc方法中的代碼,執(zhí)行完畢后在執(zhí)行內(nèi)部實(shí)現(xiàn)。
開(kāi)發(fā)者并沒(méi)有實(shí)現(xiàn)dealloc方法的情況下,直接執(zhí)行系統(tǒng)內(nèi)部方法調(diào)用。
dealloc 方法的作用是什么 ?為什么會(huì)暴露出來(lái)給開(kāi)發(fā)者 ?
dealloc的作用就是釋放當(dāng)前接收器占用的內(nèi)存空間。
暴露出來(lái)是提供給開(kāi)發(fā)者重寫(xiě)的 ,用來(lái)釋放編碼過(guò)程中用到的通知、Observer 等需要手動(dòng)管理釋放的操作方法。
dealloc 方法內(nèi)部都做了些什么呢 ?
來(lái)自于 Apple 官方開(kāi)源代碼 objc4 -779 的源碼分析
一 、dealloc 調(diào)用流程
1.首先調(diào)用 _objc_rootDealloc()
2.接下來(lái)調(diào)用 rootDealloc()
isTaggedPointer 是否是標(biāo)記指針 是直接 return ;
接下來(lái)會(huì)判斷是否可以被直接快速釋放,判斷的依據(jù)主要有 5 個(gè),判斷是否有以下五種情況
nonpointer 是否優(yōu)化過(guò)isa指針
weakly_reference 是否存在弱引用指向
has_assoc 是否設(shè)置過(guò)關(guān)聯(lián)對(duì)象
has_cxx_dtor 是否有cpp的析構(gòu)函數(shù)(.cxx_destruct)
has_sidetable_rc 引用計(jì)數(shù)器是否過(guò)大無(wú)法存儲(chǔ)在isa中
如果有以上五種任意一種,將會(huì)調(diào)用 object_dispose()方法,做下一步的處理。
如果沒(méi)有之前五種情況的任意一種,則可以執(zhí)行釋放操作,C 函數(shù)的 free()。
執(zhí)行完畢。
二、object_dispose() 調(diào)用流程。
直接調(diào)用 objc_destructInstance()。
之后調(diào)用C的 free() 函數(shù)。
-
objc_destructInstance() 調(diào)用流程
先判斷 hasCxxDtor,是否有析構(gòu)函數(shù)(析構(gòu)器),要調(diào)用 object_cxxDestruct() ,釋放(清除成員變量)。
再判斷hasAssocitatedObjects,如果有的話(huà),要調(diào)用object_remove_associations(), 移除當(dāng)前對(duì)象的關(guān)聯(lián)對(duì)象。
然后調(diào)用 objc_clear_deallocating()。
-
執(zhí)行完畢。
屏幕快照 2020-05-07 下午12.06.20.png
-
objc_clear_deallocating() 調(diào)用流程。
-
調(diào)用clearDeallocating()
屏幕快照 2020-05-07 下午12.09.53.png 判斷isa是否優(yōu)化過(guò),從arm64架構(gòu)開(kāi)始,對(duì)isa進(jìn)行了優(yōu)化,變成了一個(gè)共用體(union)結(jié)構(gòu),所以結(jié)果一般是優(yōu)化過(guò)了。
判斷是否有弱引用或者引用計(jì)數(shù)
-
執(zhí)行 clearDeallocating_slow()
步驟2到4 再執(zhí)行 weak_clear_no_lock,在這一步驟中,會(huì)將指向該對(duì)象的弱引用指針置為nil。
-
接下來(lái)執(zhí)行 table.refcnts.eraser(),從引用計(jì)數(shù)表中擦除該對(duì)象的引用計(jì)數(shù)。
屏幕快照 2020-05-07 下午12.20.30.png .至此為止,Dealloc 的執(zhí)行流程結(jié)束。
-
三、weak_clear_no_lock調(diào)用流程
- 去掉所有指向的弱指針
- 調(diào)用weak_entry_remove:從區(qū)域的弱引用表中刪除條目。
/**
* Called by dealloc; nils out all weak pointers that point to the
* provided object so that they can no longer be used.
*
* @param weak_table
* @param referent The object being deallocated.
*/
void
weak_clear_no_lock(weak_table_t *weak_table, id referent_id)
{
objc_object *referent = (objc_object *)referent_id;
weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
if (entry == nil) {
/// XXX shouldn't happen, but does with mismatched CF/objc
//printf("XXX no entry for clear deallocating %p\n", referent);
return;
}
// zero out references
weak_referrer_t *referrers;
size_t count;
if (entry->out_of_line()) {
referrers = entry->referrers;
count = TABLE_SIZE(entry);
}
else {
referrers = entry->inline_referrers;
count = WEAK_INLINE_COUNT;
}
for (size_t i = 0; i < count; ++i) {
objc_object **referrer = referrers[i];
if (referrer) {
if (*referrer == referent) {
*referrer = nil;
}
else if (*referrer) {
_objc_inform("__weak variable at %p holds %p instead of %p. "
"This is probably incorrect use of "
"objc_storeWeak() and objc_loadWeak(). "
"Break on objc_weak_error to debug.\n",
referrer, (void*)*referrer, (void*)referent);
objc_weak_error();
}
}
}
weak_entry_remove(weak_table, entry);
}
那么開(kāi)發(fā)者重寫(xiě)dealloc后可以做什么,不可以做什么呢 ?
可以做什么 :
從 NotificationCenter remove observer、remove KVO, 有些非ARC管理的比如CFRelease , 有些需要流關(guān)閉,用了RAC持有disposable對(duì)象的可以dispose,這些都是比較常見(jiàn)的。還有一些會(huì) removeGestureRecognizer, addToRunLoop 的removeFromRunLoop, dispatch_release掉自己持有的queue, 不過(guò)這些可能不是必要。
不可以做:
1 . 不要調(diào)用[super dealloc],實(shí)際上想調(diào)用也調(diào)用不了。。。 ARC編譯器會(huì)自動(dòng)調(diào)用,寫(xiě)了會(huì)直接報(bào)錯(cuò)程序無(wú)法運(yùn)行;
- 不要使用點(diǎn)語(yǔ)法,建議使用_property 進(jìn)行存取。因?yàn)辄c(diǎn)語(yǔ)法會(huì)觸發(fā)setter 、getter方法,如果這些方法被重寫(xiě),實(shí)現(xiàn)了一些不知道的操作,可能會(huì)涉及或者觸發(fā)一些不應(yīng)該在dealloc階段做的事情比如對(duì)屬性做了KVO監(jiān)聽(tīng)。
因?yàn)檫@個(gè)方法暴露出來(lái)的目的就是為了讓開(kāi)發(fā)者來(lái)處理對(duì)象實(shí)例變量以外的資源。