weak详解
本文将深入探讨iOS中weak引用的实现原理,包括底层数据结构、核心函数实现、生命周期管理,以及weak、unowned、unsafe_unretained三者的对比。 weak的基本概念 weak是一种弱引用修饰符,它不会增加对象的引用计数,也就是说不会持有对象。当对象被释放时,所有指向该对象的weak引用会自动被置为nil,这是weak最核心的特性。 // Objective-C中使用weak @property (nonatomic, weak) id<SomeDelegate> delegate; __weak NSObject *weakObj = strongObj; // Swift中使用weak weak var delegate: SomeDelegate? weak var weakObj = strongObj weak的底层数据结构 要理解weak的实现原理,首先需要了解几个核心数据结构。 SideTable SideTable是Runtime中非常重要的数据结构。关于SideTable在引用计数存储中的作用,请参考iOS中的内存管理-侧表存储。 struct SideTable { os_unfair_lock slock; // 锁,保证线程安全 RefcountMap refcnts; // 引用计数哈希表 weak_table_t weak_table; // 弱引用表 }; 系统维护了一个固定大小的SideTable数组,称为StripedMap。通过对对象地址做哈希和取模来定位对应的SideTable: // 通过对象地址获取对应的SideTable static SideTable& table = SideTables()[obj]; // 内部等效逻辑:index = hash(obj) % StripeCount // StripeCount为StripedMap的大小 由于对象数量远大于SideTable数量,多个对象会被映射到同一个SideTable,这类似于哈希表中的哈希冲突。这种设计的核心目的是分散锁竞争——每个SideTable拥有独立的锁,不同SideTable上的操作可以并行执行,相比单一全局表大幅提升了多线程性能。 weak_table_t weak_table_t是存储弱引用关系的哈希表,采用 开放寻址法(线性探测) 解决哈希冲突: struct weak_table_t { weak_entry_t *weak_entries; // 连续分配的数组,作为开放寻址哈希表的底层存储 size_t num_entries; // 当前已使用的条目数量 uintptr_t mask; // 容量掩码(= 数组容量 - 1),用于 hash & mask 快速取模 uintptr_t max_hash_displacement; // 最大哈希冲突偏移量 }; 虽然 weak_entries 的类型是 weak_entry_t *(即一块连续内存),但元素不是按顺序填入的——插入时通过 hash(referent地址) & mask 计算目标槽位,冲突时向后线性探测。因此它本质上是一个用数组实现的开放寻址哈希表,而非普通的顺序数组。 ...