[iOS]KVOController踩坑记

KVO 作为 iOS 中一种强大并且有效的机制,为我们检测对象属性的变化提供了帮助;

但系统提供的KVO接口实在太麻烦,所以开发过程中,我们使用了facebook 开源的KVOController。

今天和大家分享一下在项目开发过程中KVOController的填坑经历。

第一个坑:

[iOS]KVOController踩坑记_第1张图片

这样使用会导致selfKVOController形成循环引用。

1. KVOController为所有的NSObject对象都提供 -KVOController 属性,所以这里self是强引用了KVOController

[iOS]KVOController踩坑记_第2张图片

2.     FBKVOController 实例方法-observer:keyPath:options:block: 调用后会强引用 self 

[iOS]KVOController踩坑记_第3张图片
[iOS]KVOController踩坑记_第4张图片

[_objectInfosMap setObject:infos forKey:object];

这里的 object 就是 -[KVOController observer:keyPath:options:block:] 传进来的第一个参数,也就是"self"

也就是把 “self” 作为 key,保存在FBKVOController的私有变量_objectInfosMap里面

就会形成 “self ----》 KVOController ----》 self” 这样的循环引用


第二个坑:

为了解决上面的循环引用问题,我把代码改成了下面酱紫,iOS10必崩


KVOControllerNonRetainingKVOController 的区别就是初始化的时候,retainObservedNO

[iOS]KVOController踩坑记_第5张图片
[iOS]KVOController踩坑记_第6张图片

上面“坑一”说到,“self” 是被 _objectInfosMap 强引用了,retainObserved 传 NO,就可以解决这个问题

但是事情并没有这样结束。接下来的测试,ios10的系统必崩


[iOS]KVOController踩坑记_第7张图片

这是 "self" 释放了,但是没有调用到 removeObserver 的崩溃栈

-[FBKVOController _unobserveAll] 里面调试,发现 _objectInfosMap 中已经没有了 “self”

调用顺序是这样的:

1. [self dealloc]

2. [FBKVOController dealloc]

3. [FBKVOController dealloc] 里面找存起来的"self",并调用 [self removeObserver] 

因为第3步中,“self”已经被释放,FBKVOController 中对“self” weak 指针已经置 nil

所以最终并没有调用到 “self” 的 removeObserver

[iOS]KVOController踩坑记_第8张图片


总结:

一、对象监听自己的属性变化,应该在setter中监听;而不应该使用 -[self.KVOController observe:self]

二、对象dealloc时,指向对象的weak指针已经置为nil

你可能感兴趣的:([iOS]KVOController踩坑记)