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安全移除
相关推荐
美狐美颜sdk4 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭9 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin
泓博10 小时前
Objective-c把字符解析成字典
开发语言·ios·objective-c
Daniel_Coder10 小时前
Xcode 中常用图片格式详解
ios·xcode·swift
瓜子三百克11 小时前
Objective-C 路由表原理详解
开发语言·ios·objective-c
帅次11 小时前
Objective-C面向对象编程:类、对象、方法详解(保姆级教程)
flutter·macos·ios·objective-c·iphone·swift·safari
RyanGo14 小时前
iOS断点下载
ios·swift
蒙小萌199314 小时前
找工作-iOS开发-3年经验-AI协作开发
ios
丶皮蛋菌16 小时前
关于OC与Swift内存管理的解惑
ios
杂雾无尘17 小时前
掌握生死时速:苹果应用加急审核全攻略!
ios·swift·apple