下面是runtime中关于ARC的数据结构部分:
Weak引用实现
NSObject中定义了两个方法:
id objc_storeWeak(id *location, id newObj)
{
return storeWeak<true/*old*/, true/*new*/, true/*crash*/>
(location, (objc_object *)newObj);
}
id objc_storeWeakOrNil(id *location, id newObj)
{
return storeWeak<true/*old*/, true/*new*/, false/*crash*/>
(location, (objc_object *)newObj);
}
第二个方法与第一个作用类似,都是调用的storeWeak模版函数,只不过第三个模版参数传入的值是false,表示如果要存储的值释放了或者要存储的值的类不支持weak引用,就会存储一个nil,而不是crash掉。
Runtime会维护一个SideTables,如下代码所示:
alignas(StripedMap<SideTable>) static uint8_t
SideTableBuf[sizeof(StripedMap<SideTable>)];
static void SideTableInit() {
new (SideTableBuf) StripedMap<SideTable>();
}
//SideTables就是一个StripedMap,id为key,值为SideTable
static StripedMap<SideTable>& SideTables() {
return *reinterpret_cast<StripedMap<SideTable>*>(SideTableBuf);
}
而SideTables就是一个StripedMap,它以id为key,sideTable为值。那么SideTable的结构式什么样子呢?如下:
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table;
SideTable() {
memset(&weak_table, 0, sizeof(weak_table));
}
~SideTable() {
_objc_fatal("Do not delete SideTable.");
}
void lock() { slock.lock(); }
void unlock() { slock.unlock(); }
bool trylock() { return slock.trylock(); }
// Address-ordered lock discipline for a pair of side tables.
template<bool HaveOld, bool HaveNew>
static void lockTwo(SideTable *lock1, SideTable *lock2);
template<bool HaveOld, bool HaveNew>
static void unlockTwo(SideTable *lock1, SideTable *lock2);
};
我们关注的是weak_table_t这个数据结构,它针对这个对象的weak引用表。如下:
struct weak_table_t {
weak_entry_t *weak_entries;//引用项
size_t num_entries;//引用次数
uintptr_t mask;
uintptr_t max_hash_displacement;
};