Swift iOS导航返回报错咨询:如何正确返回或跳转页面?
解决 "Attempt to present on whose view is not in the window" 问题及正确的页面跳转/返回方式
首先得帮你拆解下这个警告的核心原因:你当前调用present(_:animated:completion:)的那个视图控制器,它的视图已经不在App的窗口层级里了——要么是这个VC已经被dismiss掉,要么是它本身就没被正确添加到导航栈或窗口中,导致系统找不到它的视图来承载新弹出的控制器。
接下来针对你的场景,给出靠谱的返回和跳转方案:
一、正确的页面返回方式
如果你的ScoreViewController是通过present方式弹出来的,返回上一页的正确姿势是在当前的ScoreViewController实例里调用dismiss方法,别去操作已经被隐藏的原VC:
// 在ScoreViewController的按钮点击事件或逻辑里写 @IBAction func backButtonTapped(_ sender: UIButton) { dismiss(animated: true, completion: nil) }
要是你的原VC是嵌入在导航控制器里的,也可以用导航栈的popViewController(animated:),但前提是你当初是用push而不是present跳转到ScoreVC的。
二、避免报错的正确跳转方式
你现在的跳转代码本身没问题,但要确保调用这段代码的VC是当前处于活跃状态、视图确实在窗口层级里的控制器。给你两个实用建议:
- 别在已经被dismiss的VC的异步回调(比如网络请求的completion)里调用这段代码——此时这个VC的视图早就不在窗口里了,自然会报错。
- 如果是在全局工具类或者非活跃VC里跳转,最好先获取当前窗口的最顶层可见控制器,再用它来present:
// 先写个工具方法获取最顶层可见控制器 func getTopVisibleViewController() -> UIViewController? { guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return nil } var topVC = keyWindow.rootViewController while let presentedVC = topVC?.presentedViewController { topVC = presentedVC } return topVC } // 然后用这个顶层控制器来跳转 if let topVC = getTopVisibleViewController(), let scoreVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ScoreViewController") as? ScoreViewController { topVC.present(scoreVC, animated: true, completion: nil) }
额外提醒
- 尽量别在非活跃的VC(比如已经被dismiss、或者还没加载完成的VC)里执行页面跳转操作。
- 如果你的页面结构是基于导航控制器的,优先用
pushViewController(_:animated:)和popViewController(animated:)来管理页面栈,这样层级更清晰,也不容易踩窗口层级的坑。
内容的提问来源于stack exchange,提问作者user9683424
相关产品推荐
相关产品推荐

