544 字
3 分钟
weak实现原理
iOS-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 */idobjc_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表中所有该地址的记录删除