如何在关联对象上使用 weak
要在 category 中定义属性, 唯一的办法就是使用关联对象.
但是关联对象的存储方式只有 assign, retain, copy 三种, 并没有 weak. 想要使用 weak 属性就要自己想办法了.
例如
我们自定义类如下
1 | @interface MyObject : NSObject |
测试的时候, 在一个 viewcontroller 的 viewDidLoad 中, 我们定义一个 MyObject 对象, 并对其中的 weakObj 赋值.
1 | - (void)viewDidLoad { |
在 viewDidDisappear 中去获取值
1 | -(void)viewDidDisappear:(BOOL)animated { |
如果我们 weakvalue 是一个使用 weak 定义的属性, 在 viewDidDisappear 中访问的时候将会变成nil.
那么如果需要使用关联对象, 需要如何存储这个 weakvalue 呢?
直接使用 assign
1 | void *weakValueKey = NULL; |
不用怀疑, 属性不会自动值为 nil, 如果在对象释放之后访问, 将会导致野指针错误
解决方案
最简单的解决方案就是使用 block 包起来. 先来看代码
1 | -(void)setWeakvalue:(NSObject *)weakvalue { |
运行结果
原理解析:
首先我们在 setter 方法里面使用了一个 weak 的局部变量 weakObj 来实现实际的 weak 对象储存. block 会捕获这个对象, 但是由于是 weak 对象, 并不会增加引用计数.
然后, 我们将这个 block 存放在关联对象中, 这样在 getter 中, 如果weakvalue 指向的对象还未释放, 则会正确返回, 如果已经释放, block 内部捕获的 weak 对象自然也会置空.