15.weak实现原理
描述
系统维护了一个
hash
表,Key
是所指对象的地址,Value
是weak
指针的地址数组弱引用,应用对象的引用计数不会+1
并在对象被释放的时候自动设为
nil
,这是和assign
本质的区别,用assign
修饰对象的话会发生野指针的问题
实现过程
初始化时
runtime
调用objc_initWeak
函数创建一个新的weak
指针指向修饰的对象的地址
//初始化weak表
/**
* Initialize a fresh weak pointer to some object location.
* It would be used for code like:
*
* (The nil case)
* __weak id weakPtr;
* (The non-nil case)
* NSObject *o = ...;
* __weak id weakPtr = o;
*
* @param addr Address of __weak ptr.
* @param val Object ptr.
*/
id objc_initWeak(id *addr, id val)
{
*addr = 0;
if (!val) return nil;
return objc_storeWeak(addr, val); // 存储weak对象
}
添加引用时
objc_initWeak
会调用objc_storeWeak
函数,更新指针指向,创建对应弱引用表
/**
* This function stores a new value into a __weak variable. It would
* be used anywhere a __weak variable is the target of an assignment.
*
* @param location The address of the weak pointer itself
* @param newObj The new object this weak ptr should now point to
*
* @return \e newObj
*/
id
objc_storeWeak(id *location, id newObj)
{
id oldObj;
SideTable *oldTable;
SideTable *newTable;
spinlock_t *lock1;
#if SIDE_TABLE_STRIPE > 1
spinlock_t *lock2;
#endif
// Acquire locks for old and new values.
// Order by lock address to prevent lock ordering problems.
// Retry if the old value changes underneath us.
retry:
oldObj = *location;
oldTable = SideTable::tableForPointer(oldObj);
newTable = SideTable::tableForPointer(newObj);
lock1 = &newTable->slock;
#if SIDE_TABLE_STRIPE > 1
lock2 = &oldTable->slock;
if (lock1 > lock2) {
spinlock_t *temp = lock1;
lock1 = lock2;
lock2 = temp;
}
if (lock1 != lock2) spinlock_lock(lock2);
#endif
spinlock_lock(lock1);
if (*location != oldObj) {
spinlock_unlock(lock1);
#if SIDE_TABLE_STRIPE > 1
if (lock1 != lock2) spinlock_unlock(lock2);
#endif
goto retry;
}
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
newObj = weak_register_no_lock(&newTable->weak_table, newObj, location);
// weak_register_no_lock returns nil if weak store should be rejected
// Set is-weakly-referenced bit in refcount table.
if (newObj && !newObj->isTaggedPointer()) {
newObj->setWeaklyReferenced_nolock();
}
// Do not set *location anywhere else. That would introduce a race.
*location = newObj;
spinlock_unlock(lock1);
#if SIDE_TABLE_STRIPE > 1
if (lock1 != lock2) spinlock_unlock(lock2);
#endif
return newObj;
}
weak_unregister_no_lock
旧对象解除注册*
weak_register_no_lock
新对象添加注册
释放时
调用
objc_release
引用计数为0调用
dealloc
dealloc
中调用了_objc_rootDealloc
函数_objc_rootDealloc
调用了object_dispose
调用
objc_destructInstance
objc_destructInstance
首先根据对象地址获取所有weak
指针地址数组,遍历置为nil
,然后把这weak
表中所有该地址的记录删除
Last updated
Was this helpful?