Application tried to present modally an active controller

本文探讨了iOS应用中模态视图控制器重复激活引发的问题及解决方案。首次模态展示正常,但在二次模态时出现错误。文章分析了问题原因,并提供了解决方案:确保每次模态结束后正确销毁控制器。

控制器模态到另一个控制器发生了错误。报错是Application 试图模态到一个活跃的控制器中。

第一次模态的时候不会出现问题,第二次发生了问题。

也就是说明了第二次模态的视图是活跃状态,没有销毁。

查找代码,发现了问题,第一次模态之后,控制器不是通过dismiss回到之前的控制器,而是通过其他的方式。

这时候就需要我们在第一次模态之后,跳到之前页面的时候,把当前视图控制器销毁,置nil。

然后我们再模态到这个视图就没有问题了。

这个错误表明你尝试模态展示一个已经存在于其他容器(`TPContainerNavigationController`)中的视图控制器 (`MineMainViewController`),而 iOS 不允许重复将同一个控制器添加到多个层级中。以下是问题和解决方案的分析: --- ### **问题原因** 1. **控制器已存在父容器** - `MineMainViewController` 已经被添加到某个导航控制器(`TPContainerNavigationController`)中,但你又尝试用 `showDetailViewController(_:sender:)` 展示它。 - `showDetailViewController` 是 `UISplitViewController` 的方法,但你的代码中 **错误地直接对 `self`(可能是普通视图控制器)调用了它**,而非对 `splitVC` 调用。 2. **逻辑混乱** - 你创建了 `splitVC` 并配置了它的子控制器(`masterNavi` 和 `detailNavi`),但最终没有将 `splitVC` 展示到界面上,而是尝试用 `showDetailViewController` 展示一个独立的 `vc`(`MineMainViewController`)。 --- ### **解决方案** #### **方案1:正确使用 `splitVC` 作为根控制器** 如果你想切换到分栏布局,应该将 `splitVC` 设为窗口的根控制器或通过模态展示: ```swift @objc func jumpToMine() { let splitVC = BaseSplitViewController() let vc = UIStoryboard(name: "Mine", bundle: nil).instantiateViewController(withIdentifier: "mineEntry") as! MineMainViewController // 左侧主视图(直接复用 vc 或创建新控制器) let masterVC = UIViewController() // 或其他左侧控制器 let detailVC = vc // 将 MineMainViewController 作为右侧详情 let masterNavi = BaseNavigationController(rootViewController: masterVC) let detailNavi = BaseNavigationController(rootViewController: detailVC) splitVC.viewControllers = [masterNavi, detailNavi] splitVC.preferredDisplayMode = .oneBesideSecondary // 适配不同 iOS 版本的列宽 if #available(iOS 11.0, *) { splitVC.preferredPrimaryColumnWidthFraction = 0.5 splitVC.maximumPrimaryColumnWidth = .greatestFiniteMagnitude } else { splitVC.minimumPrimaryColumnWidth = UIScreen.main.bounds.width * 0.5 splitVC.maximumPrimaryColumnWidth = UIScreen.main.bounds.width * 0.5 } // 替换根控制器或模态展示 if let window = UIApplication.shared.delegate?.window?? { window.rootViewController = splitVC } // 或模态展示(需确保当前控制器在导航栈中) // present(splitVC, animated: true) } ``` #### **方案2:修复 `showDetailViewController` 的调用** 如果 `self` 是 `UISplitViewController` 的子控制器(例如在分栏的 `masterNavi` 中),应该对 **分栏控制器** 调用 `showDetailViewController`: ```swift @objc func jumpToMine() { let vc = UIStoryboard(name: "Mine", bundle: nil).instantiateViewController(withIdentifier: "mineEntry") as! MineMainViewController // 确保当前控制器在分栏控制器的上下文中 if let splitVC = self.splitViewController { let detailNavi = BaseNavigationController(rootViewController: vc) splitVC.showDetailViewController(detailNavi, sender: self) // 正确调用 } else { // 如果不在分栏上下文中,回退到导航或模态展示 navigationController?.pushViewController(vc, animated: true) } } ``` #### **方案3:避免重复使用控制器实例** 如果 `MineMainViewController` 已经存在于其他层级中,应该创建新的实例: ```swift @objc func jumpToMine() { // 创建新的实例,避免复用已存在的控制器 let newVC = UIStoryboard(name: "Mine", bundle: nil).instantiateViewController(withIdentifier: "mineEntry") as! MineMainViewController // 根据上下文选择展示方式 if let splitVC = self.splitViewController { splitVC.showDetailViewController(BaseNavigationController(rootViewController: newVC), sender: self) } else { navigationController?.pushViewController(newVC, animated: true) } } ``` --- ### **关键修复点** 1. **不要直接对 `self` 调用 `showDetailViewController`** - 该方法必须由 `UISplitViewController` 或其子控制器调用。 2. **确保控制器实例唯一性** - 避免将同一个 `UIViewController` 实例添加到多个父容器中。 3. **明确界面切换目标** - 如果目标是分栏布局,应将 `splitVC` 设为根控制器或模态展示。 - 如果目标是导航跳转,直接 `pushViewController`。 --- ### **最终推荐代码** 假设你的应用需要切换到分栏布局: ```swift @objc func jumpToMine() { // 1. 创建分栏控制器 let splitVC = BaseSplitViewController() let mineVC = UIStoryboard(name: "Mine", bundle: nil).instantiateViewController(withIdentifier: "mineEntry") as! MineMainViewController // 2. 配置左侧菜单(示例) let menuVC = UIViewController() menuVC.view.backgroundColor = .lightGray let masterNavi = BaseNavigationController(rootViewController: menuVC) // 3. 配置右侧内容 let detailNavi = BaseNavigationController(rootViewController: mineVC) // 4. 组装分栏控制器 splitVC.viewControllers = [masterNavi, detailNavi] splitVC.preferredDisplayMode = .oneBesideSecondary // 5. 适配列宽 if #available(iOS 11.0, *) { splitVC.preferredPrimaryColumnWidthFraction = 0.5 splitVC.maximumPrimaryColumnWidth = .greatestFiniteMagnitude } else { let screenWidth = UIScreen.main.bounds.width splitVC.minimumPrimaryColumnWidth = screenWidth * 0.5 splitVC.maximumPrimaryColumnWidth = screenWidth * 0.5 } // 6. 替换根控制器(或模态展示) if let window = UIApplication.shared.delegate?.window?? { UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve) { window.rootViewController = splitVC } } } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值