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)会为trueisBeingDismissed:当模态弹出的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
相关产品推荐
相关产品推荐

