返回导航栈前一视图时弹出模态视图的正确实现咨询
解决在导航栈前一视图显示模态框的正确方式
这个问题我之前踩过坑!你当前的写法之所以会触发警告,核心原因是时机不对:在viewWillDisappear执行时,当前ViewController已经进入了脱离导航栈的流程,这时候你拿到的navigationController?.viewControllers.last其实是一个即将被detached的VC,系统自然会警告你不要在这种状态下present模态框,甚至极端情况可能导致模态框无法正常显示或者出现内存问题。
下面给你两种靠谱的实现方式,都是在导航栈切换完成、目标VC完全处于活跃状态时触发present操作:
方法一:利用导航控制器代理(通用场景)
这种方法适合所有导航栈返回的场景(不管是系统返回按钮还是自定义返回按钮),通过UINavigationControllerDelegate的回调来确保时机正确:
- 让当前ViewController遵守
UINavigationControllerDelegate协议 - 在
viewDidLoad中设置代理 - 在导航栈切换完成的回调里判断目标VC,然后present模态框
class CurrentViewController: UIViewController, UINavigationControllerDelegate { override func viewDidLoad() { super.viewDidLoad() // 设置导航控制器代理 navigationController?.delegate = self } func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { // 替换成你的前序ViewController类型,判断当前显示的是不是目标页面 guard viewController is PreviousViewController else { return } // 初始化并present你的模态框 let myModalView = MyModalViewController() viewController.present(myModalView, animated: true, completion: nil) // 重要:如果只需要触发一次,记得清空代理,避免后续导航操作重复触发 navigationController.delegate = nil } }
方法二:在pop的回调中处理(主动返回场景)
如果是你自己调用popViewController触发的返回,可以直接在pop的completion闭包里处理,逻辑更直接:
@IBAction func customBackButtonTapped(_ sender: UIButton) { navigationController?.popViewController(animated: true) { [weak self] in // 确保持有导航控制器,且栈顶是目标VC guard let topVC = self?.navigationController?.topViewController else { return } let myModalView = MyModalViewController() topVC.present(myModalView, animated: true, completion: nil) } }
额外注意事项
- 不要在
viewWillDisappear/viewDidDisappear里做present操作,这两个生命周期方法里当前VC的状态已经不稳定了 - 如果用代理方法,一定要记得在触发后清空代理,或者在回调里加更精准的判断逻辑,避免影响其他页面的导航操作
- 尽量给模态框加上
animated: true,符合iOS的交互规范,提升用户体验
内容的提问来源于stack exchange,提问作者John Montgomery
相关产品推荐
相关产品推荐

