iOS 11中NavigationController Push操作失效问题求助
问题分析与解决方案
这个问题我在iOS11适配阶段也碰到过,核心原因是iOS11开始严格校验导航栈的状态:当你present新导航控制器N的过渡动画还未完成时,直接在A中调用pushViewController修改导航栈,系统会判定此时栈状态不稳定,从而拦截操作并抛出提示:while an existing transition or presentation is occurring; the navigation stack will not be updated。
具体解决方案
方案1:在视图完全显示后执行Push(最可靠)
将Push操作放在A的viewDidAppear(_:)方法中,这个方法会在present过渡动画完全结束、视图已经显示在屏幕上后触发,此时导航栈状态稳定,可以安全执行Push:
class ViewControllerA: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 可选:确保只执行一次Push,避免重复触发 guard !(navigationController?.topViewController is ViewControllerB) else { return } let vcB = ViewControllerB() navigationController?.pushViewController(vcB, animated: true) } }
方案2:利用Present的Completion回调触发Push
在M中present N的时候,通过completion闭包监听present操作完成,直接在回调中执行Push操作,从根源上避免过渡冲突:
// 在M中执行present的代码 let vcA = ViewControllerA() let navN = UINavigationController(rootViewController: vcA) present(navN, animated: true) { // Present动画完成后立即Push B let vcB = ViewControllerB() vcA.navigationController?.pushViewController(vcB, animated: true) }
方案3:检查过渡状态后执行Push
如果必须在某个特定时机执行Push,可以先检查导航控制器是否正在进行过渡动画,若正在过渡则延迟执行:
extension ViewControllerA { func pushToViewControllerB() { guard let nav = navigationController else { return } // 判断当前是否有正在进行的过渡动画 if nav.transitionCoordinator?.isAnimating == true { // 延迟到主线程下一次循环再尝试 DispatchQueue.main.async { self.pushToViewControllerB() } return } let vcB = ViewControllerB() nav.pushViewController(vcB, animated: true) } }
额外说明
iOS11之前的系统没有这么严格的状态校验,所以不会出现这个提示,但其实在旧系统中这种操作也存在潜在的栈状态异常风险,只是系统没有暴露错误信息。上述方案不仅能解决iOS11的问题,也能提升整体代码的稳定性。
内容的提问来源于stack exchange,提问作者BalKrishan Yadav
相关产品推荐
相关产品推荐

