iOS应用调用dismiss方法崩溃:UITabBarController模态弹窗场景
我之前也碰到过类似的场景,你这个崩溃大概率和视图控制器的层级关系或者dismiss的调用对象错误有关,下面给你几个实用的排查和解决方向:
1. 确保调用 dismiss 的对象正确
因为ViewController2被包裹在UINavigationController里,如果你直接在ViewController2里调用self.dismiss(animated: true),很容易因为导航控制器的层级嵌套导致逻辑混乱。推荐两种更稳妥的写法:
// 方法1:让导航控制器执行dismiss self.navigationController?.dismiss(animated: true, completion: nil) // 方法2:直接找到发起present的控制器来执行dismiss self.presentingViewController?.dismiss(animated: true, completion: nil)
另外要注意:别在ViewController2的deinit方法或者异步回调里调用dismiss,这种场景下很容易出现控制器已被释放的野指针问题。
2. 排查是否存在重复 dismiss 或控制器提前释放的情况
有时候重复触发dismiss操作,或者ViewController1在ViewController2未完成dismiss就被回收(比如UITabBarController切换标签导致ViewController1被释放),都会抛出异常。可以做这两个检查:
- 给dismiss按钮加状态锁,防止重复点击:
var isDismissing = false @IBAction func dismissBtnTapped(_ sender: UIButton) { guard !isDismissing else { return } isDismissing = true self.navigationController?.dismiss(animated: true) { [weak self] in self?.isDismissing = false } }
- 在ViewController1里添加
deinit打印,确认是否在dismiss前就被释放:
deinit { print("ViewController1 已被释放") }
如果dismiss操作触发前就打印了这句话,说明ViewController1被提前回收了,需要检查UITabBarController的配置,比如是不是viewControllers被意外替换或者设置了不合理的懒加载逻辑。
3. 检查模态转场的配置是否异常
如果present时用了自定义转场动画,或者设置了非默认的modalPresentationStyle,也可能导致dismiss崩溃。可以先尝试用默认配置测试:
// ViewController1中present的代码,先改成全屏模态试试 let vc2 = ViewController2() let nav = UINavigationController(rootViewController: vc2) nav.modalPresentationStyle = .fullScreen self.present(nav, animated: true)
如果这样就不崩溃了,说明问题出在你之前的模态样式或转场动画上,再针对性调整即可。
4. 查看详细崩溃日志定位问题
你目前只看到了libc++abi的通用报错,其实可以在Xcode的崩溃报告里找到更具体的异常信息——比如是不是NSInvalidArgumentException,提示“Attempt to dismiss view controller which is not presenting”之类的。根据具体错误信息能更快定位根源,比如这个提示就说明你调用dismiss的控制器根本不是被present出来的,或者它的presentingViewController已经不存在了。
内容的提问来源于stack exchange,提问作者JoseMartinFit

