KVO是个好东西,但使用不当将导致巨坑——甚至应用崩溃都不在话下。下面就是一个典型案例。
1 问题描述
使用第三方框架ViewDeck实现侧滑出现隐藏View的功能。具体步骤为:
①创建IIViewDeckController
(带有leftController和centerController)
1 | // ViewController.m |
②从当前控制器的navigationController
使用pushViewController
方法进入新创建的控制器
③使用向右拖动左侧边缘的手势pop这个控制器,注意不要松手,向左拖动取消这个手势
④使用手势或返回按钮pop这个控制器,应用崩溃,如下图
2 分析
根据错误信息可以初步判断Crash是由于页面Dealloc时KVO没有remove导致的。但查看ViewDeck源码,发现在IIViewDeckController.m
的dealloc
方法中已经对KVO做了remove处理。。。
1 | // IIViewDeckController.m |
既然KVO是有remove的,那么会不会是多次添加KVO造成remove不彻底呢?果然,经过调试,发现在使用手势Pop页面时,如果取消手势,viewWillAppear
方法会触发,而“bounds”这个KVO是在这个方法中addObserver
的,所以就造成了KVO重复添加的现象。
3 总结
警惕viewWillAppear的执行时机viewWillAppear
并不只在页面出现时触发,如上文,还可能在手势pop页面取消时触发。所以:
尽量不要在viewWillAppear
中进行页面初始化的操作,如果非做不可,建议使用全局变量判断页面是否已经加载。这个问题也适用于以下几个方法viewDidAppear
viewWillDisappear
viewDidDisappear
举一反三,在使用NotificationCenter
也需要注意不能多次添加,并注意及时remove。
这个Bug已经通过PullRequest方式反馈给了ViewDeck作者
https://github.com/ViewDeck/ViewDeck/pull/521