KVO remove observer引发的crash

文章分析了KVO在使用过程中由于未正确配对add observer和remove observer导致的crash问题。当控制器在未加载视图的情况下被释放时,可能会触发此错误。具体场景是在UITabBarController的子控制器中开启KVO监听,如果没有选中该控制器,退出时控制器会直接被释放,从而引发bug。解决方案是对添加和移除观察者进行适当处理,确保在正确的时间点进行操作。

crash日志:

*** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <XXXViewController 0x7ff158707f80> for the key path "xxx" from <XXXViewController 0x7ff158707f80> because it is not registered as an observer.'

分析原因:在使用KVO时,add observer和remove observer都是配对出现的,首先添加成为观察者,然后在释放内存的时候移除。例如:
 

    override func viewDidLoad() {
        super.viewDidLoad()
        AppUnreadNumManager.instance.addObserver(self, forKeyPath: "xxx", options: .new, context: nil)
    }
    deinit {
        AppUnreadNumManager.instance.removeObserver(self, forKeyPath: "xxx", context: nil)
    }

通常情况下,这样写是没有问题的,但是有时候控制器可能还没有加载(viewDidLoad方法没走),然后就被释放了(deinit方法走了),这样就会出现上面那个bug。

我项目中出现这个bug的原因是:我在某个控制器开启KVO监听,正好它又是UITabBarController的子控制器,在没有选中该控制器的情况下,它的viewDidLoad方法是不会走的。如果这时候直接退出UITabBarController,那么该控制器就会直接被释放,这样就会出现还没添加观察者就移除观察者的bug。

解决方案

    var isViewDidLoad = false

    override func viewDidLoad() {
        super.viewDidLoad()
        isViewDidLoad = true
        AppUnreadNumManager.instance.addObserver(self, forKeyPath: "xxx", options: .new, context: nil)
    }
    deinit {
        if isViewDidLoad {
            AppUnreadNumManager.instance.removeObserver(self, forKeyPath: "xxx", context: nil)
        }
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值