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

如何在App进入sceneWillResignActive/后台时关闭UISheetPresentationController

解决App进入后台时关闭UISheetPresentationController的问题

当前点击齿轮图标会以UISheetPresentationController形式弹出SettingsViewController,同时App进入前台的sceneDidBecomeActive方法中会检查通知权限,若权限禁用则弹出UIAlertController。但如果此时SettingsViewController仍处于显示状态,会触发"already presenting"的报错,因此需要在App进入sceneWillResignActive或sceneDidEnterBackground时自动关闭该sheet。

方法一:通过SceneDelegate生命周期方法关闭

步骤1:在主ViewController中添加关闭逻辑

在弹出SettingsViewController的主控制器中,实现检查并关闭sheet的方法:

class ViewController: UIViewController {
    // ... 现有代码 ...
    
    func dismissSettingsSheetIfNeeded() {
        // 判断当前展示的是否是SettingsViewController
        if presentedViewController is SettingsViewController {
            dismiss(animated: false) // 非动画关闭,避免后台时的视觉异常
        }
    }
}

步骤2:在SceneDelegate中调用关闭方法

在SceneDelegate的sceneWillResignActive或sceneDidEnterBackground方法中,获取主控制器并执行关闭操作:

func sceneWillResignActive(_ scene: UIScene) {
    guard let windowScene = scene as? UIWindowScene,
          let rootNav = windowScene.windows.first?.rootViewController as? UINavigationController,
          let mainVC = rootNav.topViewController as? ViewController else {
        return
    }
    mainVC.dismissSettingsSheetIfNeeded()
}

方法二:监听系统通知自动关闭

如果不想依赖SceneDelegate,可让主ViewController监听App状态变化通知:

步骤1:注册通知并实现关闭逻辑

在主ViewController的viewDidLoad中注册通知,同时编写关闭方法:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 监听App即将失去活跃状态的通知
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(dismissSettingsSheet),
            name: UIApplication.willResignActiveNotification,
            object: nil
        )
        // 也可监听进入后台的通知:UIApplication.didEnterBackgroundNotification
    }
    
    @objc private func dismissSettingsSheet() {
        if presentedViewController is SettingsViewController {
            dismiss(animated: false)
        }
    }
    
    deinit {
        // 移除通知观察者
        NotificationCenter.default.removeObserver(self)
    }
}

额外优化:保存SettingsViewController引用(可选)

如果需要更精确控制,可在弹出时保存SettingsViewController的引用,关闭时直接使用:

class ViewController: UIViewController {
    private var presentedSettingsVC: UIViewController?
    
    @IBAction func settings(_ sender: Any) {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "SettingsViewController")
        
        if let presentationController = viewController.presentationController as? UISheetPresentationController {
            presentationController.detents = [.medium(), .large()]
        }
        
        present(viewController, animated: true)
        presentedSettingsVC = viewController // 保存引用
    }
    
    @objc private func dismissSettingsSheet() {
        presentedSettingsVC?.dismiss(animated: false)
        presentedSettingsVC = nil // 清空引用
    }
}

通过以上任意一种方式处理后,App进入后台或即将失去活跃状态时,SettingsViewController会被自动关闭,回到前台时弹出UIAlertController就不会触发"already presenting"的错误。

内容的提问来源于stack exchange,提问作者Paul S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:25:23