关闭通知设置浮层/从应用设置返回时viewWillAppear不触发如何解决
问题原因
viewWillAppear 属于视图控制器的生命周期方法,仅在当前控制器的视图被添加/移除出App视图层级、或者被其他控制器弹出/覆盖时才会触发。你遇到的两类场景均为系统级行为,不会触发当前VC的生命周期回调:
- 通知设置浮层是系统级弹窗,不属于当前App的视图层级,不会影响你业务VC的生命周期
- 跳转到系统设置App是将当前App切到后台,你的VC视图没有被移除,自然不会触发生命周期方法
解决方案
你可以通过监听系统通知的方式覆盖这两类场景,以下是可直接落地的实现方案:
方案1:监听App全局活跃通知(兼容所有iOS版本)
只要App从非活跃状态恢复到前台活跃,就会触发该通知,完全覆盖你提到的关闭系统浮层、从设置页返回两个场景。
- 在视图控制器的
viewDidLoad中添加观察者:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(handleAppBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil ) }
- 实现回调方法,可自行添加判断确保只有当前VC对用户可见时才执行业务逻辑:
@objc private func handleAppBecomeActive() { // 仅当前VC已加载且在视图层级中时执行逻辑 guard isViewLoaded, view.window != nil else { return } // 在这里写你原本要在viewWillAppear中执行的逻辑,比如刷新权限状态、更新UI }
- 页面销毁时移除观察者避免内存泄漏:
deinit { NotificationCenter.default.removeObserver( self, name: UIApplication.didBecomeActiveNotification, object: nil ) }
方案2:监听场景活跃通知(适用于iOS 13+多场景App)
如果你的App支持多窗口,使用场景级的通知更精准,避免其他窗口活跃导致的误触发:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(handleSceneBecomeActive), name: UIScene.didActivateNotification, object: view.window?.windowScene ) } @objc private func handleSceneBecomeActive() { guard isViewLoaded, view.window != nil else { return } // 执行业务逻辑 }
扩展优化
如果需要区分「是从系统设置页返回」还是「其他场景切回前台」,可以添加标记位做判断:
// 标记是否是主动跳转到设置页 private var isJumpedToSettings = false // 你原本跳转设置的按钮点击方法 @IBAction func openSettingsButtonTapped(_ sender: UIButton) { isJumpedToSettings = true guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else { return } UIApplication.shared.open(settingsUrl) } @objc private func handleAppBecomeActive() { guard isViewLoaded, view.window != nil else { return } if isJumpedToSettings { // 只有从设置页返回才执行的专属逻辑 isJumpedToSettings = false // 用完重置标记位 } // 所有切回前台都要执行的通用逻辑 }
内容的提问来源于stack exchange,提问作者D C T
相关产品推荐
相关产品推荐

