在ARC中,weak指針修飾的變量會(huì)在指向的對(duì)象銷毀時(shí)自動(dòng)置為nil,系統(tǒng)是怎么做到的呢?這里從本質(zhì)和源碼出發(fā)來(lái)解釋。源碼
iOS系統(tǒng)中維護(hù)著一個(gè)SideTables的哈希表,這個(gè)哈希表用來(lái)管理所有對(duì)象的引用計(jì)數(shù)和weak指針。
一、找到weak指針存儲(chǔ)的位置
SideTables哈希表里面裝著的元素的key為對(duì)象,value為SideTable的結(jié)構(gòu)體!
struct SideTable {
spinlock_t slock;
RefcountMap refcnts; // 引用計(jì)數(shù)
weak_table_t weak_table; // 弱引用表
}
由上面可知weak_table_t是系統(tǒng)保存weak指針的結(jié)構(gòu)。
存儲(chǔ)weak指針的結(jié)構(gòu)體weak_table_t
struct weak_table_t {
weak_entry_t *weak_entries;
size_t num_entries;
};
typedef DisguisedPtr<objc_object *> weak_referrer_t;
#define WEAK_INLINE_COUNT 4
struct weak_entry_t {// 本來(lái)是一個(gè)C++結(jié)構(gòu)體, 簡(jiǎn)化后如下
DisguisedPtr<objc_object> referent;
weak_referrer_t *referrers;
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
};
由上可知:
-
referent是存儲(chǔ)被引用對(duì)象的地址. -
inline_referrers是用來(lái)裝weak指針的數(shù)組,不過(guò)數(shù)量只有WEAK_INLINE_COUNT=4個(gè). -
referrers也是存儲(chǔ)weak指針的數(shù)組,但是當(dāng)inline_referrers不夠的時(shí)候才會(huì)使用的.
二、系統(tǒng)在對(duì)象銷毀時(shí)的做法
在對(duì)象銷毀時(shí)會(huì)做的事情,根據(jù)源碼追蹤重要的步驟:
- 調(diào)用
dealloc _objc_rootDealloc(self);obj->rootDealloc();object_dispose(this);- 先調(diào)用
objc_destructInstance(obj);清楚對(duì)象相關(guān)聯(lián)的東西, 之后再調(diào)用free(obj);釋放對(duì)象。 -
objc_destructInstance(obj);會(huì)做的事情
// This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj);// 清除屬性關(guān)聯(lián)
obj->clearDeallocating();
-
clearDeallocating函數(shù)里面會(huì)調(diào)用clearDeallocating_slow(); -
clearDeallocating_slow();里面會(huì)調(diào)用weak_clear_no_lock(&table.weak_table, (id)this);。 -
weak_clear_no_lock函數(shù)中將referrers數(shù)組或者inline_referrers數(shù)組遍歷,賦值為nil。