iOS-KVOController问题分析

前言

苹果的KVO键值观察机制在日常开发中很常见,但是系统提供的API却不支持block回调;再加上添加观察者addObserver:forKeyPath:options:context:只能观察一个键值,并且还要手动的移除键值观察,这些存在的问题导致开发者对现有的机制十分的不满意,涌现出很多的解决方案,自己实现KVO机制(runtime)以及今天要介绍的KVOController库,KVOController是由FaceBook开源的一个KVO库,通过封装系统的KVO机制,能够支持block回调以及隐式移除键值监听等功能,支持设置多个KeyPaths,而且线程安全。

 

KVOController使用

详细的介绍不是今天要讲述的内容,网络上有很多的文章,分析了其源码的逻辑,大致原理将键值观察信息封装至_FBKVOInfo对象,然后在FBKVOController类中维护着_objectInfosMap表,类型为NSMapTable(是一种类似于NSDictionary的数据结构,可以对Key和Value进行内存管理),Key为observing被观察者对象,最后通过_FBKVOSharedController类,实现键值监听以及回调;当前的控制器被释放掉后,会自动执行键值观察移除操作,因为FBKVOController对象通过runtime关联当前控制器。

//简单的使用
[self.KVOController observe:hashObject keyPath:@"className" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
    NSLog(@"str -- %@", change[NSKeyValueChangeNewKey]);
}];
hashObject.className = @"有点意思";

observe是被观察的对象,观察者对象是_FBKVOSharedController这个对象。

 

KVO崩溃的一般原因

1、被观察者被释放了(被观察者对象是一个局部变量);

2、观察者被释放了,但是没有移除键值监听;

3、注册的监听没有被移除掉,又重新注册了一遍监听;

官网上也有说明,If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its deallocation method. If your app targets earlier releases, be sure to invoke removeObserver:name:object: before observer or any object specified in addObserver:selector:name:object: is deallocated.大概意思,iOS9之前的系统,必须要在观察者对象被释放之前显式执行移除键值观察逻辑(原因2)。

 

问题分析

NSMapTable可以由开发者自行的设置管理内存的方案,当使用WeakMemory时即使用self.KVOControllerNonRetaining对象去设置键值观察时,当前控制器Pop后程序会直接crash,原因是由于被观察者对象被释放掉,导致_objectInfosMap表中的内容自动移除,为什么会这样?官方文档中有解释,The major option is to have keys and/or values held “weakly” in a manner that entries are removed when one of the objects is reclaimed.大概的意思就是,当key或者是value使用weak内存管理时,只要key或者value对象被释放,当前的记录将会被移除。记录被移除后,执行_unobserveAll移除键值观察逻辑时,无法移除已注册的键值观察,因为保存在_objectInfosMap中的信息被移除掉了。结合KVO的崩溃的原因,造成崩溃是由被观察者被释放导致。

 

建议

因此在使用KVOController库时,尽量的使用self.KVOController对象去绑定键值观察,因为_objectInfosMap会持有observing对象并不会立即释放掉,直到执行完移除键值观察后,清除_objectInfosMap记录,才会被释放掉,这样就不会造成Pop控制器导致系统crash的问题,其他的方法在KVOController的github地址的issues中有讨论,感兴趣的开发者可以关注。

转载于:https://my.oschina.net/u/1450995/blog/1522730

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值