You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:13:32