在ARC中,weak指针修饰的变量会在指向的对象销毁时自动置为nil,系统是怎么做到的呢?这里从本质和源码出发来解释。源码
iOS系统中维护着一个SideTables
的哈希表,这个哈希表用来管理所有对象的引用计数和weak指针。
一、找到weak指针存储的位置
SideTables
哈希表里面装着的元素的key为对象,value为SideTable的结构体!
struct SideTable {
spinlock_t slock;
RefcountMap refcnts; // 引用计数
weak_table_t weak_table; // 弱引用表
}
由上面可知weak_table_t是系统保存weak指针的结构。
存储weak指针的结构体weak_table_t
struct weak_table_t {
weak_entry_t *weak_entries;
size_t num_entries;
};
typedef DisguisedPtr<objc_object *> weak_referrer_t;
#define WEAK_INLINE_COUNT 4
struct weak_entry_t {// 本来是一个C++结构体, 简化后如下
DisguisedPtr<objc_object> referent;
weak_referrer_t *referrers;
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
};
由上可知:
-
referent
是存储被引用对象的地址. -
inline_referrers
是用来装weak指针的数组,不过数量只有WEAK_INLINE_COUNT
=4个. -
referrers
也是存储weak指针的数组,但是当inline_referrers
不够的时候才会使用的.
二、系统在对象销毁时的做法
在对象销毁时会做的事情,根据源码追踪重要的步骤:
- 调用
dealloc
_objc_rootDealloc(self);
obj->rootDealloc();
object_dispose(this);
- 先调用
objc_destructInstance(obj);
清楚对象相关联的东西, 之后再调用free(obj);
释放对象。 -
objc_destructInstance(obj);
会做的事情
// This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj);// 清除属性关联
obj->clearDeallocating();
-
clearDeallocating
函数里面会调用clearDeallocating_slow();
-
clearDeallocating_slow();
里面会调用weak_clear_no_lock(&table.weak_table, (id)this);
。 -
weak_clear_no_lock
函数中将referrers
数组或者inline_referrers
数组遍历,赋值为nil。
网友评论