銷毀的源頭
調(diào)用-release改览,release會(huì)調(diào)用:
uintptr_t objc_object::sidetable_release(bool performDealloc)
sidetable_release():
以下是runtime源碼 NSObject.mm
1584行
bjc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
SideTable& table = SideTables()[this];
bool do_dealloc = false;
//加鎖
table.lock();
//獲取當(dāng)前對(duì)象所在的sidetable(一個(gè)hash表),在sidetable.refcnts(RefcountMap,一個(gè)map)中查到當(dāng)前對(duì)象的迭代器
RefcountMap::iterator it = table.refcnts.find(this);
//接著判斷迭代器是否是指向了sidetable的end
//如果是就代表找不到:
if (it == table.refcnts.end()) {
//將對(duì)象標(biāo)記為“正在析構(gòu)”
//標(biāo)記需要dealloc
do_dealloc = true;
table.refcnts[this] = SIDE_TABLE_DEALLOCATING;
} else if (it->second < SIDE_TABLE_DEALLOCATING) {
//判斷之前存儲(chǔ)的引用計(jì)數(shù)值是否為 0,避免負(fù)數(shù)
//將對(duì)象標(biāo)記為“正在析構(gòu)”
//標(biāo)記需要dealloc
// SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.
do_dealloc = true;
it->second |= SIDE_TABLE_DEALLOCATING;
} else if (! (it->second & SIDE_TABLE_RC_PINNED)) {
//將引用計(jì)數(shù)減一
it->second -= SIDE_TABLE_RC_ONE;
}
//解鎖
table.unlock();
if (do_dealloc && performDealloc) {
//調(diào)用對(duì)象的dealloc方法:
((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);
}
return do_dealloc;
}
如果調(diào)用了dealloc:
進(jìn)行以下過程時(shí)低滩,不能再創(chuàng)建有新的 __weak引用,否則會(huì)crash
遞歸調(diào)用父類的-dealloc
如果是 MRC 代碼,則需要手動(dòng)釋放實(shí)例變量
最后調(diào)用NSObject的dealloc
NSObject的dealloc會(huì)調(diào)用
_objc_rootDealloc(self);
_objc_rootDealloc(id obj) NSObject.mm
1838行
_objc_rootDealloc(id obj)
{
//是否還活著 斷言
assert(obj);
//調(diào)用 objc_object::rootDealloc()
obj->rootDealloc();
}
objc_object::rootDealloc() objc_object.h
415行
objc_object::rootDealloc()
{
//是否使用TaggedPointer優(yōu)化 是直接人突然
if (isTaggedPointer()) return; // fixme necessary?
//不需要處理object_dispose的所有內(nèi)容
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
!isa.has_cxx_dtor &&
!isa.has_sidetable_rc))
{
assert(!sidetable_present());
free(this);
}
else {
//調(diào)用object_dispose
object_dispose((id)this);
}
}
object_dispose(id obj) objc-runtime-new.mm
6313行
id object_dispose(id obj)
{
//是否為nil 直接返回
if (!obj) return nil;
//調(diào)用 void *objc_destructInstance(id obj)
objc_destructInstance(obj);
free(obj);
return nil;
}
void *objc_destructInstance(id obj) objc-runtime-new.mm
6290行
void *objc_destructInstance(id obj)
{
//如果不為nil 才處理
if (obj) {
//是否有析構(gòu)函數(shù) 這個(gè)bool值取決于當(dāng)前類以及父類往上是否有實(shí)例變量,如果有實(shí)例變量當(dāng)前類就有.cxxDestruct欺抗,當(dāng)前類或父類有此方法值=YES售碳,都沒有才=NO
bool cxx = obj->hasCxxDtor();
//是否有關(guān)聯(lián)對(duì)象
bool assoc = obj->hasAssociatedObjects();
// This order is important.
//如果有析構(gòu)函數(shù) 調(diào)用 void object_cxxDestruct(id obj)
if (cxx) object_cxxDestruct(obj);
//如果有關(guān)聯(lián)對(duì)象 移除關(guān)聯(lián)對(duì)象
if (assoc) _object_remove_assocations(obj);
//調(diào)用objc_clear_deallocating()清空引用計(jì)數(shù)表
obj->clearDeallocating();
}
return obj;
}
void object_cxxDestruct(id obj) objc-class.mm
473行
void object_cxxDestruct(id obj)
{
//如果為nil 直接retun
if (!obj) return;
//是否使用TaggedPointer優(yōu)化 是直接return
if (obj->isTaggedPointer()) return;
//調(diào)用 static void object_cxxDestructFromClass(id obj, Class cls)
object_cxxDestructFromClass(obj, obj->ISA());
}
static void object_cxxDestructFromClass(id obj, Class cls) objc-class
447行
static void object_cxxDestructFromClass(id obj, Class cls)
{
void (*dtor)(id);
// Call cls's dtor first, then superclasses's dtors.
//往父類遞歸調(diào)用.cxxDestruct 直到hasCxxDtor=NO return結(jié)束
for ( ; cls; cls = cls->superclass) {
if (!cls->hasCxxDtor()) return;
dtor = (void(*)(id))
lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
if (dtor != (void(*)(id))_objc_msgForward_impcache) {
if (PrintCxxCtors) {
_objc_inform("CXX: calling C++ destructors for class %s",
cls->nameForLogging());
}
(*dtor)(obj);
}
}
}
.cxx_destruct
ARC下?lián)碛袑?shí)例變量才會(huì)有這個(gè)方法,通過Clang CodeGen生成,MRC都需要手動(dòng)release所以不需要
ARC下會(huì)遍歷當(dāng)前對(duì)象所有的實(shí)例變量通過objc_storeStrong() release掉
具體實(shí)現(xiàn)過程:https://blog.sunnyxx.com/2014/04/02/objc_dig_arc_dealloc/
void objc_removeAssociatedObjects(id object) objc-runtime
635行
void objc_removeAssociatedObjects(id object)
{
if (object && object->hasAssociatedObjects()) {
_object_remove_assocations(object);
}
}
void _object_remove_assocations(id object) objc-references
316行
關(guān)聯(lián)對(duì)象都存放在AssociationsHashMap中,以obj為key,以存放關(guān)聯(lián)對(duì)象的ObjectAssociationMap為value,然后拿到ObjectAssociationMap中的所有ObjcAssociation對(duì)象,然后此對(duì)象調(diào)用ReleaseValue(),繼而調(diào)用releaseValue绞呈,然后調(diào)用objc_release
void _object_remove_assocations(id object) {
vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
if (associations.size() == 0) return;
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// copy all of the associations that need to be removed.
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
elements.push_back(j->second);
}
// remove the secondary table.
delete refs;
associations.erase(i);
}
}
// the calls to releaseValue() happen outside of the lock.
for_each(elements.begin(), elements.end(), ReleaseValue());
}
struct ReleaseValue {
void operator() (ObjcAssociation &association) {
releaseValue(association.value(), association.policy());
}
};
static void releaseValue(id value, uintptr_t policy) {
if (policy & OBJC_ASSOCIATION_SETTER_RETAIN) {
return objc_release(value);
}
}
void objc_clear_deallocating(id obj) NSObject.mm
1705行
void
objc_clear_deallocating(id obj)
{
assert(obj);
if (obj->isTaggedPointer()) return;
obj->clearDeallocating();
}
objc_object::clearDeallocating() objc-object.h
399行
inline void
objc_object::clearDeallocating()
{
if (slowpath(!isa.nonpointer)) {
// Slow path for raw pointer isa.
//調(diào)用sidetable_clearDeallocating()把對(duì)象的weak指針置nil,把對(duì)象的計(jì)數(shù)引用移除
sidetable_clearDeallocating();
}
else if (slowpath(isa.weakly_referenced || isa.has_sidetable_rc)) {
/判斷是否有過弱引用 是否因?yàn)橛?jì)數(shù)太大有多個(gè)sidetable
// Slow path for non-pointer isa with weak refs and/or side table data.
//調(diào)用clearDeallocating_slow();內(nèi)部再分開判斷各自實(shí)現(xiàn)sidetable_clearDeallocating的內(nèi)容
clearDeallocating_slow();
}
assert(!sidetable_present());
}
相信看了上面的源碼分析 對(duì)于下面這種圖 父類有屬性贸人,關(guān)聯(lián)對(duì)象,子類有屬性關(guān)聯(lián)對(duì)象佃声,此時(shí)創(chuàng)建個(gè)[SubClass new]然后釋放掉艺智,這幾個(gè)類的dealloc打印順序是什么應(yīng)該也清楚了,當(dāng)然屬性之間dealloc順序圾亏,關(guān)聯(lián)對(duì)象之間順序還需要注意力惯,同一個(gè)類多個(gè)屬性的dealloc順序是倒序,
- 屬性列表的順序:
分類屬性1召嘶,分類屬性2父晶,類擴(kuò)展屬性1,類擴(kuò)展屬性2弄跌,類屬性1甲喝,類屬性2
- 屬性的dealloc銷毀順序是:
類擴(kuò)展屬性2,類擴(kuò)展屬性1铛只,類屬性2埠胖,類屬性1,然后再銷毀父類的屬性
關(guān)聯(lián)對(duì)象添加的成員變量是先銷毀子類的成員變量淳玩,在銷毀父類的直撤,在同一個(gè)類里添加的順序不一定,因?yàn)榈讓邮谴鎯?chǔ)在無序map中蜕着,所以dealloc順序不一定
runtime源代碼下載地址
搜索objc4 選擇數(shù)字最大的即為最新的(并不是最下面的就是最新的谋竖,看數(shù)字大小)