對(duì)象回收時(shí)Weak指針自動(dòng)被置為nil的實(shí)現(xiàn)原理

前言

我們都知道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--;

}

}

簡(jiǎn)單來說,這個(gè)方法首先根據(jù)對(duì)象地址獲取所以Weak指針地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個(gè)entry從Weak表中刪除。

這里只簡(jiǎn)單說說對(duì)象回收時(shí),Weak指針如何設(shè)為nil,至于Weak指針如何注冊(cè)到Weak表中、如何維護(hù)可以參考o(jì)bjc-weak.m中的其它源碼。從實(shí)現(xiàn)中可以看出,Weak指針的使用涉及到Hash表的增刪改查,有一定的性能開銷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容