iOS中点击UINavigationController返回按钮能否中断viewWillDisappear执行?
核心问题说明
你没法在viewWillDisappear里中断返回流程,因为这个方法被调用时,视图控制器已经进入出栈流程,无法终止,必须在pop动作触发前做校验拦截。
实现方案
方案1:自定义导航栏返回按钮(全iOS版本兼容,通用性最强)
直接替换系统默认返回按钮,点击时先做业务校验,校验通过再执行返回逻辑,同时可兼容侧滑返回手势的校验:
- 首先在
viewDidLoad中配置自定义返回按钮和侧滑手势代理
override func viewDidLoad() { super.viewDidLoad() // 替换系统默认返回按钮 let backButton = UIBarButtonItem(image: UIImage(systemName: "chevron.backward"), style: .plain, target: self, action: #selector(backButtonTapped)) navigationItem.leftBarButtonItem = backButton // 配置侧滑返回手势代理,实现侧滑时也触发校验 navigationController?.interactivePopGestureRecognizer?.delegate = self }
- 实现返回按钮点击校验逻辑
@objc private func backButtonTapped() { // 替换为你自己的业务校验条件,比如此处判断名称不能为空 guard let name = nameField.text, !name.isEmpty else { // 条件不满足,弹出提示,不执行返回 let alert = UIAlertController(title: "提示", message: "名称为必填项,请填写后再返回", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "知道了", style: .default)) present(alert, animated: true) return } // 条件满足,执行返回 navigationController?.popViewController(animated: true) }
- 实现侧滑手势的校验逻辑
extension DetailViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { guard gestureRecognizer == navigationController?.interactivePopGestureRecognizer else { return true } // 和返回按钮共用同样的校验逻辑 guard let name = nameField.text, !name.isEmpty else { let alert = UIAlertController(title: "提示", message: "名称为必填项,请填写后再返回", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "知道了", style: .default)) present(alert, animated: true) return false } return true } }
方案2:使用导航控制器代理拦截(iOS16+ 更简洁)
iOS16新增了导航控制器的pop拦截代理方法,不需要自定义返回按钮即可实现拦截:
// 在viewDidLoad中设置代理 override func viewDidLoad() { super.viewDidLoad() navigationController?.delegate = self } // 实现代理方法 extension DetailViewController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, shouldPop viewController: UIViewController) -> Bool { // 只拦截当前详情页的pop动作 guard viewController === self else { return true } // 替换为你的业务校验条件 guard let name = nameField.text, !name.isEmpty else { let alert = UIAlertController(title: "提示", message: "名称为必填项,请填写后再返回", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "知道了", style: .default)) present(alert, animated: true) return false } return true } }
注意:使用该方案时如果多个页面都用到了导航控制器代理,需要注意代理的切换,避免互相冲突。
你原有代码viewWillDisappear中的保存逻辑不需要修改,只有校验通过执行返回时才会触发该方法,保存逻辑会正常执行。
内容的提问来源于stack exchange,提问作者Iggy
相关产品推荐
相关产品推荐

