You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于网络状态弹出/关闭UIAlertController在蜂窝数据下崩溃如何解决?

问题原因及修复方案

核心触发原因

  • 你使用的isBeingPresented判断条件逻辑存在缺陷:该属性仅在弹窗执行present动画的过程中为true,当弹窗完全展示在界面上后就会变为false。蜂窝网络切换时网络状态会短时间内连续触发多次回调,当第二次触发网络断开的逻辑时,isBeingPresented已经为false,代码会再次调用present方法尝试展示已经在视图层级中的弹窗,触发崩溃。
  • 主队列操作错误使用了DispatchQueue.main.sync:同步派发会阻塞当前网络监听队列,极端情况下会触发主队列死锁,同时连续状态变更的同步执行也会放大状态判断的误差。
  • 没有对弹窗是否已经被添加到视图层级做判断:仅靠动画状态的判断无法覆盖所有场景,需要额外校验弹窗的presentingViewController是否存在。

修复后的代码

class ViewController: UIViewController {
    
    var monitor = NWPathMonitor()
    
    let networkQueue = DispatchQueue(label: "InternetConnectionMonitor")
    var textInternet : Bool = true
    var internetPopUp : UIAlertController!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.internetPopUp = UIAlertController(title: "Internet Connection", message: "Currently, the device is not connected to Internet, as soon as will be connected the alert will dissapear.", preferredStyle: .alert)
        startMonitoring()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // 页面销毁时停止监听,避免内存泄漏
        monitor.cancel()
    }
    
    //check internet connection
    func startMonitoring(){
        monitor.pathUpdateHandler = { [weak self] path in
            guard let self = self else { return }
            let isSatisfied = path.status == .satisfied
            // 替换sync为async,避免死锁和队列阻塞
            DispatchQueue.main.async {
                self.textInternet = isSatisfied
                self.pop()
            }
        }
        
        monitor.start(queue: networkQueue)
    }
    
    func pop(){
        textInternet ? popDownAlert() : popUpAlert()
    }
         
    //func popUp Alert
    func popUpAlert(){
        // 新增presentingViewController判断,避免重复present
        guard internetPopUp.presentingViewController == nil,
              !internetPopUp.isBeingPresented,
              !internetPopUp.isBeingDismissed else {
            return
        }
        present(internetPopUp, animated: true)
    }
    
    //func popDown Alert
    func popDownAlert() {
        guard internetPopUp.presentingViewController != nil,
              !internetPopUp.isBeingDismissed,
              !internetPopUp.isBeingPresented else {
            return
        }
        internetPopUp.dismiss(animated: true)
    }
}

额外优化点

  • 回调中增加了[weak self]避免循环引用导致的内存泄漏
  • 页面消失时调用monitor.cancel()停止网络监听,释放资源
  • 简化了状态判断逻辑,减少冗余代码

内容的提问来源于stack exchange,提问作者Mr Astronaut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 16:18:02