美文网首页零碎知识点iOS干货
KVO没有添加监听的情况下移除观察者导致崩溃

KVO没有添加监听的情况下移除观察者导致崩溃

作者: CoderAO | 来源:发表于2016-03-23 18:40 被阅读4124次

问题:在使用KVO的时候,如果在没有添加监听的情况下进行观察者移除,会导致程序的崩溃.

这个问题看起来有点脑残,如果没有添加为什么还要移除, 但是我确实遇到了,它的情景是这样的:

问题背景
如上图:这是一个典型的以UITabBarController为根控制器的应用.
各个控制器的用途在图中都有标出,其中在C控制器中,如果用户点击了退出登录按钮,我的处理方式是切换程序的根控制器(如果不是这样的做法可能就不会有这个问题了).

问题来了,当我启动app的时候,由于A是默认控制器, 就会首先执行A控制器的viewDidLoad:方法, 而B控制器的viewDidLoad:方法在我们点击按钮B的时候才会调用,B控制器才会添加对KVO的监听.

当然,我们也可以通过其他方法使B的viewDidLoad:方法提前调用,但这不在我们这篇文章的讨论范围.

那么,如果app启动后我没有点击B控制器而是直接进入C控制器并点击了退出登录, 这时进行了根控制器的切换,整个tabBarController都会被释放,从而B控制器也就来到了dealloc方法(移除对KVO的监听).这就是为什么,B控制器为什么会在没有添加监听的情况下就会被移除观察者.

查了很久发现苹果并没有给我们提供一个判断是否已经添加观察者的方法,最后不得不采取了这个比较猥琐的方法:

// 在B控制器中
- (void)dealloc {
  @try {
    [[ATBlueTooth shareInstance] removeObserver:self forKeyPath:@"isBluetoothConnecting"];
  }
  @catch (NSException *exception) {
  }
}

相关文章

网友评论

  • 0无敌小宋0:牛逼,果然很猥琐:smile:
  • LD_左岸:出现了和您一样的问题 您这有点猥琐的方法 并不管用啊 还是崩
  • PGOne爱吃饺子:你好,请问如何让B的viewDidLoad方法提前加载的,谢谢
    CoderAO:你可以思考一下viewDidLoad的调用时机,通常是我们要用到这个控制器的view的时候.
    那怎么提前用到这个控制器的view呢?比如你在启动程序的时候给这个控制器view设置一个背景颜色:joy: xxxViewController.view.backgroundColor = ...;
  • e48d67617cb6:我出现的问题的和楼主一模一样 的 感谢
  • 7d30e59e1b8e:我这样写还是崩溃
  • 潜鱼2016:谢谢,解决了我的燃眉之急
  • e7b86f176cf3:猥琐,但有效,赞一个!
  • 简单也好:我遇到了相同的问题,楼主的解决方法可以,先谢过
    TabBar的子VC没有点击就没有注册KVO,但是要在TabBarVC里面移除KVO,就crash,还有什么其他办法么
    CoderAO:@简单也好 一般是哪里注册哪里移除,是不是你移除的地方不对
    简单也好:@CoderAO 是的,在tabBarVC的子控制器里面注册,在tabBarVC里面写,移除子控制器里面的监听的代码
    CoderAO:@简单也好 没太懂你的意思,你是让TabBarController的子控制器注册,在TabBarController移除吗?
  • 太郎君:init时注册,dealloc时反注册
    Ethan09:@neghao remove
    nenhall:@太郎君 反注册是啥?
    CoderAO:@太郎君 也是一种解决方法,之所以没有那么做,是因为有可能用户自始至终都没有进入这个页面,那么这个页面也就没有监听的必要了,避免浪费吧.
  • 曲年:在任何时候不都不要去试图切换根视图控制器。用替代方法去解决。
    CoderAO:@曲年 隐含的什么问题
    曲年:切换根试图控制器会带来隐含的各种问题。一般采用层层覆盖视图来解决。你的退出按钮如果是退出登陆的话更不必切换了。
    CoderAO:为什么,我在很多资料上都有看过这种做法,之前也听到过一个很厉害的大神提到过

本文标题:KVO没有添加监听的情况下移除观察者导致崩溃

本文链接:https://www.haomeiwen.com/subject/ghzllttx.html