?????????iOS 在運行時維護著一個全局的弱引用表,該表是一個 hash 表,hash表的?key 是 對象本身,value 是指向該對象的所有 weak 指針的地址數組。???
/**全局的弱引用表,本質是一個hash結構,對象本身作為key, 存儲weak修飾的指針地址的weak_entry_t作為value*/
struct weak_table_t {// 保存了所有指向特地對象的 weak指針集合weak_entry_t *weak_entries;// hash數組中元素個數size_t num_entries;// hash數組的長度,而不是元素個數。比如,數組長度可能是64,而元素個數僅存了2個uintptr_t mask;// hash沖突最大次數, hash數組采用開放定址法解決hash沖突uintptr_t max_hash_displacement;
};
? ? ? ? 以下述代碼為例:
NSObject * obj = [[NSObject alloc] init];__weak NSObject *p1 = obj;
__weak NSObject *p2 = obj;NSObject ** referrer1 = &p1;
NSObject ** referrer2 = &p2;[obj release];
? ? ? ? ?hash表的key為obj,hash表的值weak_entries的referers屬性被賦值為[referrer1, referrer2];
????????當weak修飾的對象obj被銷毀時,iOS在運行時會從哈希表中查找到所有指向此對象的 weak 指針,并將其全部置為空?nil,即通過執行*referrer1 = NULL和*referrer2?= NULL,實現將p1和p2置為NULL。
weak_clear_no_lock(weak_table_t *weak_table, id referent_id) {// 在weak_table中對應的weak_entry_tobjc_object *referent = (objc_object *)referent_id;weak_entry_t *entry = weak_entry_for_referent(weak_table, referent); weak_referrer_t referrers = entry->referrers;int count = TABLE_SIZE(entry);for (size_t i = 0; i < count; ++i) {objc_object **referrer = referrers[i]; if (referrer) {// 如果weak指針確實弱引用了對象 referent,則將weak指針設置為nilif (*referrer == referent) { *referrer = nil;}}}
}
? ? ? ? iOS在ARC下通過引入weak標識, 大大減少了以前retain或assign標識的對象在被銷毀后可能出現野指針的情況,進而有效提升了代碼健壯性。