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

iOS12.4中ViewWillDisappear调用popToRootViewController崩溃求助

解决TabBar中第一个NavigationController调用popToRootViewController崩溃的问题

你遇到的这个场景其实是iOS13之前UIKit视图生命周期与导航栈操作冲突的典型问题,我来帮你拆解分析并给出可行的解决思路:

问题场景复盘

  • 你的TabBar包含5个NavigationController,第一个Nav的viewWillDisappear中调用popToRootViewController会崩溃,提示UITableView dataSource未设置,但第三个Nav执行相同操作完全正常
  • 不管animated设为true还是false都会崩溃,升级到iOS13后问题自动消失
  • 在tabBar(_:didSelect:)方法中调用第一个Nav的popToRootViewController却能正常工作

核心原因分析

iOS13之前,UIKit对TabBar切换时的视图生命周期管理不够严谨:当你切换TabBarItem时,第一个Nav的viewWillDisappear会在TabBar切换动画的过程中触发。此时调用popToRootViewController,会导致栈中的MyViewController(带UITableView的那个)被提前释放,但它的UITableView可能还在执行布局或数据源相关操作——因为视图控制器已经被释放,TableView自然找不到对应的数据源,从而抛出异常。

而第三个Nav没问题,大概率是其导航栈结构、视图控制器的释放时机和第一个Nav存在差异;tabBar(_:didSelect:)中调用正常,则是因为这个方法是在TabBar切换完全完成后触发的,此时视图生命周期状态稳定,不会出现视图控制器提前释放的情况。

可行的解决办法

按推荐优先级给你整理了几个方案:

1. 在MyViewController的deinit中置空TableView的数据源/代理(根源解决)

直接从问题的触发点入手,确保视图控制器被释放前,主动切断TableView与数据源/代理的关联:

deinit {
    tableView.dataSource = nil
    tableView.delegate = nil
}

这个方法能彻底避免“数据源未设置”的崩溃,哪怕导航栈操作时机存在问题,也不会触发异常。

2. 延迟执行pop操作(快速临时修复)

把popToRootViewController的调用延迟到主队列的后续循环,等视图切换的生命周期操作完成后再执行:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    // 延迟0.1秒,让视图切换的动画和生命周期流程先完成
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        self.popToRootViewController(animated: false)
    }
}

3. 改用viewDidDisappear执行pop

viewDidDisappear是在视图完全消失后才触发的,此时视图控制器状态稳定,不会出现子视图还在操作的情况:

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    self.popToRootViewController(animated: false)
}

缺点是用户可能会看到视图消失后再执行pop的延迟感,视觉体验略有影响。

4. 检查自定义TabBar的setBar方法是否干扰生命周期

你的自定义TabBar有setBar方法用于隐藏/显示TabBar,要确保动画过程中没有修改视图层级或约束,导致第一个Nav的视图控制器被提前释放。可以尝试在执行pop操作前,先完成TabBar的动画:

// 比如在viewWillDisappear中先完成TabBar动画再pop
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    tabBarController?.setBar(hidden: true, animated: false) { _ in
        self.popToRootViewController(animated: false)
    }
}

额外说明

你提到iOS13后问题自动解决,是因为苹果在iOS13中重构了UIKit的视图生命周期管理,尤其是优化了导航控制器和TabBar控制器的视图栈管理逻辑,从底层避免了这种视图控制器提前释放的情况。

内容的提问来源于stack exchange,提问作者frank61003

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 07:32:32