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安全移除
相关推荐
2501_9159184113 分钟前
把 iOS 性能监控融入日常开发与测试流程的做法
android·ios·小程序·https·uni-app·iphone·webview
Digitally3 小时前
如何轻松地将大型音频文件从 iPhone 发送到不同的设备
ios·iphone
catchadmin4 小时前
PHP 现在可以零成本构建原生 iOS 和 Android 应用 NativePHP for Mobile v3 发布
android·ios·php
TheNextByte14 小时前
如何将照片从 iPhone 传输到三星?
ios·iphone
2501_915921435 小时前
不用 Xcode 上架 iOS,拆分流程多工具协作完成 iOS 应用的发布准备与提交流程
android·macos·ios·小程序·uni-app·iphone·xcode
Ron丶5 小时前
iOS 旧版本 App 下载方法汇总:如何获取历史版本 IPA(2026 仍有效)
windows·经验分享·macos·ios·电脑
晴天无痕5 小时前
ios OC 获取当前控制器
ios
pop_xiaoli1 天前
OC-实现下载单例类
ios·objective-c·cocoa·xcode
denggun123451 天前
Material 和 Cupertino
macos·objective-c·cocoa
zhyongrui1 天前
SnipTrip 菜单 Liquid Glass 实现方案:结构、材质、交互与深浅色策略
ios·性能优化·swiftui·交互·开源软件·材质