前言
我們都知道Weak指針不會(huì)增加所引用對(duì)象的計(jì)數(shù),并在引用對(duì)象被回收的時(shí)候自動(dòng)被置為nil。通常用于解決循環(huán)引用問題蜕琴。那么,自動(dòng)被置為nil內(nèi)部是如何實(shí)現(xiàn)的呢宵溅?
內(nèi)部實(shí)現(xiàn) —— Weak表
Runtime維護(hù)了一個(gè)Weak表凌简,用于存儲(chǔ)指向某個(gè)對(duì)象的所有Weak指針。Weak表其實(shí)是一個(gè)哈希表恃逻,Key是所指對(duì)象的地址雏搂,Value是Weak指針的地址(這個(gè)地址的值是所指對(duì)象的地址)的數(shù)組。
在對(duì)象被回收的時(shí)候寇损,經(jīng)過層層調(diào)用畔派,會(huì)最終觸發(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--;
}
}
簡單來說润绵,這個(gè)方法首先根據(jù)對(duì)象地址獲取所以Weak指針地址的數(shù)組线椰,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個(gè)entry從Weak表中刪除尘盼。
這里只簡單說說對(duì)象回收時(shí)憨愉,Weak指針如何設(shè)為nil,至于Weak指針如何注冊(cè)到Weak表中卿捎、如何維護(hù)可以參考o(jì)bjc-weak.m中的其它源碼配紫。從實(shí)現(xiàn)中可以看出,Weak指針的使用涉及到Hash表的增刪改查午阵,有一定的性能開銷躺孝。