1.weak的基本用法
weak是弱引用,用weak來修飾、描述所引用的對象計數器并不會增加,而且weak會在引用對象被釋放時自動置為nil,這也就避免了野指針訪問壞內存而引起奔潰的情況,另外weak也可以解決循環引用。
2.weak實現原理的概括
Runtime維護了一個weak表,用于存儲指向某個對象的所有weak指針。weak表其實是一個hash(哈希)表,Key是所指對象的地址,Value是weak指針的地址(這個地址的值是所指對象指針的地址,就是地址的地址)集合(當weak指針的數量小于等于4時,是數組, 超過時,會變成hash表)。
weak的實現原理可以概括一下三步:
- 初始化時:runtime會調用objc_initWeak函數,初始化一個新的weak指針指向對象的地址。
- 添加引用時:objc_initWeak函數會調用objc_storeWeak()函數,objc_storeWeak()的作用是更新指針指向,創建對應的弱引用表。
- 釋放時,調用clearDeallocating函數。clearDeallocating函數首先根據對象地址獲取所有weak指針地址的數組,然后遍歷這個數組把其中的數據設為nil,最后把這個entry從weak表中刪除,最后清理對象的記錄。
struct SideTable {
// 保證原子操作的自旋鎖
spinlock_t slock;
// 引用計數的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
}
struct weak_table_t {
// 保存了所有指向指定對象的 weak 指針
weak_entry_t *weak_entries;
// 存儲空間
size_t num_entries;
// 參與判斷引用計數輔助量
uintptr_t mask;
// hash key 最大偏移值
uintptr_t max_hash_displacement;
};