1. 前言
我們都知道Weak指針不會增加所引用對象的計數(shù),并在引用對象被回收的時候自動被置為nil
曲稼。通常用于解決循環(huán)引用問題索绪。那么,自動被置為nil
內(nèi)部是如何實現(xiàn)的呢贫悄?
2. 內(nèi)部實現(xiàn) — Weak表
Runtime維護了一個Weak表瑞驱,用于存儲指向某個對象的所有Weak指針。Weak表其實是一個哈希表窄坦,Key是所指對象的地址唤反,Value是Weak指針的地址(這個地址的值是所指對象的地址)的數(shù)組。
在對象被回收的時候鸭津,經(jīng)過層層調(diào)用彤侍,會最終觸發(fā)下面的方法將所有Weak指針的值設(shè)為nil
。(具體定義在objc-weak.m中)
PRIVATE_EXTERN void
arr_clear_deallocating(weak_table_t *weak_table, id referent) {
{
weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
if (entry == NULL) {
/// XXX shouldn't happen, but does with mismatched CF/objc
//printf("XXX no entry for clear deallocating %p\n", referent);
return;
}
// zero out references
for (int i = 0; i < entry->referrers.num_allocated; ++i) {
id *referrer = entry->referrers.refs[i].referrer;
if (referrer) {
if (*referrer == referent) {
*referrer = nil;
}
else if (*referrer) {
_objc_inform("__weak variable @ %p holds %p instead of %p\n", referrer, *referrer, referent);
}
}
}
weak_entry_remove_no_lock(weak_table, entry);
weak_table->num_weak_refs--;
}
}
簡單來說逆趋,這個方法首先根據(jù)對象地址獲取所以Weak指針地址的數(shù)組拥刻,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil
,最后把這個entry從Weak表中刪除父泳。
這里只簡單說說對象回收時,Weak指針如何設(shè)為nil
吴汪,至于Weak指針如何注冊到Weak表中惠窄、如何維護可以參考objc-weak.m中的其它源碼。從實現(xiàn)中可以看出漾橙,Weak指針的使用涉及到Hash表的增刪改查杆融,有一定的性能開銷。