viewWillAppear与viewWillDisappear不匹配问题

由一个线上crash引起, 崩溃信息Cannot remove an observer because it is not registered as an observer.

崩溃代码如下所示:

swift 复制代码
class ObserverViewController: UIViewController {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("viewWillAppear - ADD Observer")
        FakeNetworkManager.shared.addObserver(self, forKeyPath: "networkStatus", options: [.new, .old], context: nil)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print("viewWillDisappear - REMOVE Observer")
        FakeNetworkManager.shared.removeObserver(self, forKeyPath: "networkStatus")
    }

    override func observeValue(forKeyPath keyPath: String?, of _: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print("Observed network status changed.")
    }
}
  • 崩溃原因 :账号被挤下线时系统执行viewWillDisappear进行removeObserver,但此时尚未执行addObserver
  • 当用户在某个业务场景下,被其他设备登录相同账号挤掉时
  • 此时ObserverViewController已经在页面层级中,而且已经经过了viewWillAppearviewWillDisappear过程,并且不在页面层级最上层了
  • 当前设备中需要关掉所有页面回到登录页面,此时系统主动触发了viewWillDisappear,进而导致crash

解决办法

1. try-catch方案

如果是Objective C语言的话,可以通过trycatch捕获异常

less 复制代码
- (void)safeRemoveObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath {
    @try {
        [self removeObserver:observer forKeyPath:keyPath];
    } @catch (NSException *exception) {
        DDLogError(@"exception:%@", exception);
    }
}

2. NSKeyValueObservation(Swift方案)

swift 复制代码
private func addNetworkStatusObserver() {
    networkStatusObservation = MCNetworkStatusManager.sharedInstance().observe(.networkStatus, options: [.new, .old]) { [weak self] manager, _ in
        guard let self else { return }
        let currentStatus = manager.networkStatus.rawValue
         if currentStatus > MCNetworkStatus.notReachable.rawValue {
            self.reloadSafeWithFetchTop50PrivateChatUserFullinfo(true)
        }
    }
}

private func removeNetworkStatusObserver() {
    networkStatusObservation?.invalidate()
    networkStatusObservation = nil
}

注意 :NSKeyValueObservation存在监听RawRepresentable类型数据时change结果异常的未修复bug

3. 第三方KVO组件

比如facebook的KVOController

总结

  • 核心结论 :线上复杂场景中,viewWillAppearviewWillDisappear不一定配对出现

  • 推荐方案

    • Swift项目优先使用NSKeyValueObservation
    • Objective-C项目使用try-catch安全移除
相关推荐
川石课堂软件测试44 分钟前
Android和iOS APP平台测试的区别
android·数据库·ios·oracle·单元测试·测试用例·cocoa
liusheng1 小时前
Capacitor + React 的 iOS 侧滑返回手势
前端·ios
大熊猫侯佩1 小时前
Swift 6.2 列传(第十七篇):钟灵的“雷电蟒”与测试附件
单元测试·swift·apple
2501_915918412 小时前
除了 Perfdog,如何在 Windows 环境中完成 iOS App 的性能测试工作
android·ios·小程序·https·uni-app·iphone·webview
七月巫山晴3 小时前
【iOS】NSString&NSRange&NSCharacterSet
ios·cocoa·iphone
h-189-53-6712073 小时前
2026(原创)Guideline 4.3(a) - Design - Spam苹果上架iOS审核被拒AppStore卡审解决办法思路
ios
杨武博4 小时前
ios 启动图不生效问题
ios
2501_915106326 小时前
常见 iOS 抓包工具的使用方式与组合思路
android·ios·小程序·https·uni-app·iphone·webview
SY_FC6 小时前
niapp开发的 H5 被app嵌套,H5调用ios和安卓方法
android·ios·cocoa
东坡肘子7 小时前
AT 的人生未必比 MT 更好 -- 肘子的 Swift 周报 #118
人工智能·swiftui·swift