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安全移除
相关推荐
锐意无限3 小时前
Swift 扩展归纳--- UIView
开发语言·ios·swift
符哥20083 小时前
用Apollo + RxSwift + RxCocoa搭建一套网络请求框架
网络·ios·rxswift
gjxDaniel6 小时前
Objective-C编程语言入门与常见问题
开发语言·objective-c
文件夹__iOS7 小时前
AsyncStream 进阶实战:SwiftUI 全局消息流极简实现
ios·swiftui·swift
2501_916008899 小时前
深入解析iOS机审4.3原理与混淆实战方法
android·java·开发语言·ios·小程序·uni-app·iphone
忆江南10 小时前
Flutter深度全解析
ios
山水域10 小时前
Swift 6 严格并发检查:@Sendable 与 Actor 隔离的深度解析
ios
楚轩努力变强11 小时前
iOS 自动化环境配置指南 (Appium + WebDriverAgent)
javascript·学习·macos·ios·appium·自动化
游戏开发爱好者81 天前
日常开发与测试的 App 测试方法、查看设备状态、实时日志、应用数据
android·ios·小程序·https·uni-app·iphone·webview
黑码哥1 天前
ViewHolder设计模式深度剖析:iOS开发者掌握Android列表性能优化的实战指南
android·ios·性能优化·跨平台开发·viewholder