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

iOS 10.3强制关闭时调用ViewWillDisappear,iOS 11却不调用?

嘿,这个问题确实是iOS版本间的已知行为差异,我来帮你梳理清楚并给出可行的替代方案~

关于iOS版本间的行为差异

没错,你遇到的是苹果在iOS 11时调整的视图生命周期行为:

  • 在iOS 10及更早的实体设备上,当用户强制退出App(比如双击Home键划走应用)时,系统会给当前显示的ViewController调用viewWillDisappear:——这是早期系统在终止App前会尝试完成部分视图生命周期方法导致的。
  • 但从iOS 11开始,苹果优化了App终止的逻辑,强制退出时会直接终止进程,不会再触发视图控制器的消失类方法,所以viewWillDisappear:不会被调用。
    这个版本差异属于官方隐含的行为调整,是开发者圈子里的已知兼容性问题。

替代方案:区分「正常离开页面」和「强制关闭App」

这里有几个实用的方案,你可以根据自己的场景选择:

1. 利用ViewController内置属性判断(推荐)

正常页面跳转(比如push新VC、pop回上级、dismiss模态VC)时,ViewController会有对应的状态标记,我们可以直接用这些标记来过滤掉强制关闭的情况:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    // 判断是否是正常的页面导航行为
    let isNormalNavigation = isMovingFromParent || isBeingDismissed
    if isNormalNavigation {
        // 这里执行你原本的逻辑:设置标记等
        print("用户正常离开页面,执行标记设置")
    }
}
  • isMovingFromParent:当VC被从导航栈中移除时(比如pop)会为true
  • isBeingDismissed:当模态弹出的VC被关闭时会为true
    这个方案不需要全局变量,代码简洁且无额外状态维护,是最推荐的方式。

2. 结合App生命周期事件判断

如果你的场景需要更精准的控制,可以通过监听App的终止事件,设置全局标记来区分:
首先在AppDelegate(iOS13+用SceneDelegate)中定义全局标记:

// AppDelegate.swift
var isAppTerminating = false

func applicationWillTerminate(_ application: UIApplication) {
    // App即将终止时设为true
    isAppTerminating = true
}

// 针对iOS13+的多场景应用,在SceneDelegate中补充:
func sceneWillTerminate(_ scene: UIScene) {
    isAppTerminating = true
}

然后在你的ViewController中判断:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    // 排除App被强制关闭的情况
    guard !AppDelegate.isAppTerminating else {
        return
    }
    
    // 执行原本的标记设置逻辑
    print("用户正常离开页面")
}

3. 结合后台通知辅助判断

如果需要区分「用户主动切后台」和「正常页面跳转」,可以监听App进入后台的通知:

import UIKit

class YourViewController: UIViewController {
    private var backgroundObserver: NSObjectProtocol?
    private var isAppEnteringBackground = false

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 注册进入后台的通知
        backgroundObserver = NotificationCenter.default.addObserver(
            forName: UIApplication.didEnterBackgroundNotification,
            object: nil,
            queue: .main
        ) { [weak self] _ in
            self?.isAppEnteringBackground = true
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        if !isAppEnteringBackground {
            // 执行正常离开页面的逻辑
            print("用户正常离开页面")
        }
        
        // 重置标记,避免影响下次判断
        isAppEnteringBackground = false
    }

    deinit {
        // 移除通知监听,避免内存泄漏
        if let observer = backgroundObserver {
            NotificationCenter.default.removeObserver(observer)
        }
    }
}

内容的提问来源于stack exchange,提问作者Ryan Heitner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:42:49