[toc]
weak
blogs.com/guohai-stronger/p/10161870.html
/p/2b12666b351f
weak 是弱引用, 用weak來修飾、描述所引用對象的計數器並不會加1, 而且weak會在引用對象被釋放的時候自動置為nil, 這也就避免了野指針訪問壞內存而引起崩潰的情況,
weak也可以解決循環引用。
assign 可用來修飾基本數據類型, 也可修飾OC的對象, 但如果用 assign 修飾對象類型指向的是壹個強指針, 當指向的這個指針釋放之後, 它仍指向這塊內存, 必須要手動給置為nil, 否則會產生野指針, 如果還通過此指針操作那塊內存, 會導致 EXC_BAD_ACCESS 錯誤, 調用了已經被釋放的內存空間;
而 weak 只能用來修飾OC對象, 而且相比assign比較安全, 如果指向的對象消失了, 那麽它會自動置為nil, 不會導致野指針。
ARC 是 LLVM + Runtime 互相協作的結果
開啟ARC後, LLVM編譯器會自動幫我們在相應位置生成 release、retain、autorelease
在作用域 (大括號) 結束的位置添加 release
弱引用這種, 是通過runtime處理的
編譯之後的weak, 通過 objc_ownership(weak) 實現 weak 方法, objc_ownership 字面意思是:獲得對象的所有權, 是對對象weak的初始化的壹個操作。
通過 weak 編譯解析, 可以看出 weak 是通過 runtime 初始化並維護的;
weak 和 strong 都是 OC ARC 的修飾詞, 而 strong 是通過 runtime 維護的壹個自動計數表結構。
weak 指針的地址值是所指對象指針的地址
weak 全局表 weak_table_t 中的存儲 weak 定義的對象的表結構 weak_entry_t,
weak_entry_t 是存儲在弱引用表中的壹個內部結構體, 它負責維護和存儲指向壹個對象的 所有弱引用hash表
可以看到 DisguisedPtr<objc_object *> 相當於 objc_object ** ;
即 weak_referrer_t 就是 objc_object ** 的別名
初始化weak變量時, runtime會調用 objc_initWeak 函數, 初始化新的weak指針指向對象的地址;
objc_initWeak 函數內部會調用 objc_storeWeak() 函數, objc_storeWeak() 函數的作用是用來更新指針的指向, 創建弱引用表。
在最後會調用 clearDeallocating 函數。而 clearDeallocating 函數首先根據對象的地址獲取weak指針地址的數組, 然後緊接著遍歷這個數組, 將其中的數組開始置為nil, 把這個 entry從weak 表中刪除, 最後壹步清理對象的記錄。
當 weak 指向的對象被釋放時, 編譯器如何讓 weak 指針置為nil的呢?
將弱引用存到壹個弱引用表(哈希表)中, 對象銷毀時, 就從表中取出當前對象的弱引用並清除
註: 關於 SideTable 、 weak_table_t 、 weak_entry_t 參考 《 isa指針 》