銷毀的開端
調用-release,release會調用:
uintptr_t objc_object::sidetable_release(bool performDealloc)
sidetable_release():
以下都是邏輯代碼,完整代碼得實現可以查看runtime源碼
加鎖
獲取當前對象所在的sidetable(一個hash表),在sidetable.refcnts(RefcountMap,一個map)中查到當前對象的迭代器
創建變量bool do_dealloc = false;代表是否需要dealloc
接著判斷迭代器是否是指向了sidetable的end
如果是就代表找不到:
sidetable.refcnts[this] = SIDE_TABLE_DEALLOCATING(即計數變為0)
do_dealloc = true
else if(迭代器->second(對象的計數器)是否小于 SIDE_TABLE_DEALLOCATING){
second |= SIDE_TABLE_DEALLOCATING;do_dealloc = true
}
else if(迭代器->second & SIDE_TABLE_RC_PINNED > 0){
計數器-=SIDE_TABLE_RC_ONE
}
結束,解開鎖
if(do_dealloc && performDealloc){
調用對象的dealloc方法:
((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc)
}
返回do_dealloc
如果調用了dealloc:
進行以下過程時,不能再創建有新的 __weak引用,否則會crash
- 遞歸調用父類的-dealloc
如果是 MRC 代碼,則需要手動釋放實例變量
- 最后調用NSObject的dealloc
NSObject的dealloc會調用_objc_rootDealloc(self);
_objc_rootDealloc(id obj)
if(obj是否活著){
調用obj->rootDealloc()
}else{
crash
}
objc_object::rootDealloc()
if(this是使用TaggedPointer優化){ 直接返回 }
if(不需要處理object_dispose的所有內容){ free(this)然后返回 }
調用 object_dispose((id)this)
object_dispose(id obj)
if(!obj){ 直接返回 }
調用 objc_destructInstance()
objc_destructInstance()
objc_destructInstance做的事情比較多,先說objc_destructInstance的內容,內部調用的方法后面再細說:
if(如果需要為 C++ 的實例變量們(iVars)調用析構器){
調用object_cxxDestruct(obj)
}
if(通過obj->hasAssociatedObjects()判斷是否需要解除所有使用runtime Associate關聯的對象){
//如果是TaggedPointer優化,那這個方法也會返回true
調用_object_remove_assocations(obj)
}
調用objc_clear_deallocating()
調用 free() 返回nil
object_cxxDestruct(obj)
if(!obj){return;}
if(!isTaggedPointer){return;}
調用object_cxxDestructFromClass(obj, obj->ISA());
內部會遞歸判斷自己和父類是否有.cxx_destruct方法,有的話則調用.cxx_destruct
.cxx_destruct
ARC下擁有實例變量才會有這個方法,通過Clang CodeGen生成,MRC都需要手動release所以不需要
ARC下會遍歷當前對象所有的實例變量通過objc_storeStrong() release掉
具體實現過程:https://blog.sunnyxx.com/2014/04/02/objc_dig_arc_dealloc/
_object_remove_assocations(obj)
關聯對象都存放在AssociationsHashMap中,以obj為key,以存放關聯對象的ObjectAssociationMap為value,具體操作就是把ObjectAssociationMap中的所有對象對應的Allocator拿出來,作為參數發送給ReleaseValue(),然后調用objc_release()再對關聯對象發送release
objc_clear_deallocating()
if(isa.nonpointer){
調用sidetable_clearDeallocating()把對象的weak指針置nil,把對象的計數引用移除
}
if (isa.weakly_referenced(是否有過弱引用) || isa.has_sidetable_rc(是否因為計數太大有多個sidetable)){
調用clearDeallocating_slow();內部再分開判斷各自實現sidetable_clearDeallocating的內容
}