要实现 weak 属性,首先要搞清楚 weak 属性的特点:
weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同 assign 类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。
那么 runtime 如何实现 weak 变量的自动置nil?
runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。
对象的内存销毁时间表,分四个步骤:
- 调用 -release :引用计数变为零
- 对象正在被销毁,生命周期即将结束.
- 不能再有新的 __weak 弱引用, 否则将指向 nil.
- 调用 [self dealloc]
- 子类 调用 -dealloc
- 继承关系中最底层的子类 在调用 -dealloc
- 如果是 MRC 代码 则会手动释放实例变量们(iVars)
- 继承关系中每一层的父类 都在调用 -dealloc
- NSObject 调 -dealloc
- 只做一件事:调用 Objective-C runtime 中的
- object_dispose() 方法
- 调用 object_dispose()
- 为 C++ 的实例变量们(iVars)调用 destructors
- 为 ARC 状态下的 实例变量们(iVars) 调用 -release
- 解除所有使用 runtime Associate方法关联的对象
- 解除所有 __weak 引用
- 调用 free()
验证:
生成weak属性的对象, 并指向一个对象,当对象销毁之后,指向该对象的weak属性的对象也会随之销毁。
__weak id weakObj1 = nil;
__weak id weakObj2 = nil;
{
id obj = [[NSObject alloc] init]; // 引用计数会增加,这里不会是weak的
weakObj1 = obj;
weakObj2 = obj;
NSLog(@"obj: %@", obj);
NSLog(@"weakObj1: %@", weakObj1);
NSLog(@"weakObj2: %@", weakObj2);
}
NSLog(@"weakObj1: %@", weakObj1);
NSLog(@"weakObj2: %@", weakObj2);
输出为:
obj: <NSObject: 0x60800000bdc0>
weakObj1: <NSObject: 0x60800000bdc0>
weakObj2: <NSObject: 0x60800000bdc0>
weakObj1: (null)
weakObj2: (null)
因为 weak 本身是非拥有的,所有如果是把weakObj1设置为nil的话,是不会对其他的造成影响的。
参考:<a href="http://www.dechao.net/blog/interview">吵了个吵 - iOS面试题</a>