Swift中Segue左右切换报错:试图模态展示活跃控制器
解决"Application tried to present modally an active controller"错误
错误原因分析
这个报错的核心是:你试图再次模态展示一个已经处于活跃状态(正在屏幕上显示)的视图控制器。结合你的场景,当你用SegueFromLeft从VenueDetailsVC切回VenueListVC时,你的自定义Segue大概率还是沿用了"present新控制器"的逻辑,但此时VenueListVC其实是被VenueDetailsVC模态覆盖的父控制器,或者VenueDetailsVC本身就是当前活跃的控制器,重复present必然触发错误。
针对性解决方案
方案1:修正自定义Segue的perform方法(模态转场场景)
如果你的VenueDetailsVC是通过模态方式从VenueListVC展示的,那么返回时应该用dismiss而不是present。修改你的SegueFromLeft类:
import UIKit class SegueFromLeft: UIStoryboardSegue { override func perform() { // 从Details返回List,source是VenueDetailsVC,直接dismiss即可 source.dismiss(animated: true) { // 转场完成后的回调(可选) } // 如果需要保留自定义左滑动画,可添加以下代码实现 /* source.transitioningDelegate = self source.dismiss(animated: true) */ } } // 可选:实现自定义左滑退出动画 extension SegueFromLeft: UIViewControllerTransitioningDelegate { func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return LeftSlideTransitionAnimator() } } // 自定义动画器类 class LeftSlideTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.35 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromVC = transitionContext.viewController(forKey: .from) else { return } let containerView = transitionContext.containerView // 目标位置:视图向左滑出屏幕 let finalFrame = CGRect(x: -containerView.bounds.width, y: 0, width: containerView.bounds.width, height: containerView.bounds.height) UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { fromVC.view.frame = finalFrame }) { _ in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) } } }
方案2:改用导航控制器的Push/Pop(更推荐的页面管理方式)
如果你的页面结构是基于UINavigationController的,应该用push和pop来管理页面跳转,而非模态转场:
- 对于
SegueFromRight(从List到Details):
class SegueFromRight: UIStoryboardSegue { override func perform() { guard let navController = source.navigationController else { source.present(destination, animated: true) return } navController.pushViewController(destination, animated: true) } }
- 对于
SegueFromLeft(从Details返回List):
class SegueFromLeft: UIStoryboardSegue { override func perform() { guard let navController = source.navigationController else { source.dismiss(animated: true) return } navController.popViewController(animated: true) } }
方案3:直接用按钮触发返回(最简单的实现方式)
其实返回操作完全可以不用Segue,直接在VenueDetailsVC中添加返回按钮,触发dismiss或pop:
// 在VenueDetailsVC中 @IBAction func backButtonTapped(_ sender: UIButton) { // 模态场景下用这个 dismiss(animated: true) // 导航栈场景下用这个 // navigationController?.popViewController(animated: true) }
这种方式既简单又不容易出错,自定义动画可以通过设置transitioningDelegate来实现。
额外注意事项
- 确保Storyboard中
SegueFromLeft的触发源是VenueDetailsVC中的控件(比如返回按钮),且Segue的类绑定和标识符设置正确。 - 如果用导航栈结构,一定要确认
VenueListVC已经被嵌入到UINavigationController中。
内容的提问来源于stack exchange,提问作者Roggie
相关产品推荐
相关产品推荐

