# 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`旧对象解除注册

  &#x20; \*&#x20;
* `weak_register_no_lock`新对象添加注册
  \*

### 释放时

* 调用`objc_release`
* 引用计数为0调用`dealloc`
* `dealloc`中调用了`_objc_rootDealloc`函数
* `_objc_rootDealloc`调用了`object_dispose`
* 调用`objc_destructInstance`
* `objc_destructInstance`首先根据对象地址获取所有`weak`指针地址数组,遍历置为`nil`,然后把这`weak`表中所有该地址的记录删除

```
```
