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

在UIAlertController的Action中销毁UIViewController引发崩溃求助

解决点击UIAlertController的Sign Out按钮销毁控制器时的UICollectionView崩溃问题

看起来你遇到的是一个典型的UICollectionView布局断言崩溃,通常发生在控制器销毁时机和CollectionView的布局更新不同步的时候。咱们一步步拆解问题和解决方案:

崩溃原因分析

你看到的-[UICollectionViewData validateLayoutInRect:]断言失败,本质是当你点击Sign Out按钮销毁当前控制器时,UICollectionView可能还有未完成的布局计算任务,或者控制器销毁后,CollectionView依然在尝试访问已被释放的数据源/代理对象,导致内部数据状态不一致,触发了系统的断言检查。

可行的解决方案

1. 等Alert完全消失后再销毁控制器

不要在Sign Out按钮的回调里立即销毁控制器,先让AlertController完成消失动画,确保主线程上的布局任务都结束后再执行销毁操作:

let signOutAlert = UIAlertController(title: "确认登出", message: "你确定要退出登录吗?", preferredStyle: .alert)

// 取消按钮
signOutAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel))

// 登出按钮
signOutAlert.addAction(UIAlertAction(title: "Sign Out", style: .destructive, handler: { [weak self] _ in
    // 先让弹窗消失
    signOutAlert.dismiss(animated: true) {
        // 在这里执行控制器销毁操作
        if let navController = self?.navigationController {
            navController.popViewController(animated: true)
        } else {
            // 如果是present出来的控制器,用dismiss
            self?.dismiss(animated: true)
        }
    }
}))

present(signOutAlert, animated: true)

这里一定要用[weak self]避免循环引用,确保控制器能正常被释放。

2. 提前切断CollectionView与控制器的关联

在控制器即将销毁时,手动将CollectionView的数据源和代理置为nil,防止它后续访问已释放的对象:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    // 判断控制器是否正在被移除
    if isMovingFromParent {
        collectionView.dataSource = nil
        collectionView.delegate = nil
    }
}

这个方法可以直接切断CollectionView和控制器的依赖,从根源上避免无效访问。

3. 取消未完成的异步UI更新任务

如果你的代码里有后台加载数据后更新CollectionView的逻辑,一定要在控制器销毁前取消这些任务:

// 定义一个标志位,标记控制器是否已取消
var isControllerCancelled = false

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    isControllerCancelled = true
}

// 异步加载数据的示例方法
func fetchAndUpdateData() {
    DispatchQueue.global().async { [weak self] in
        // 模拟后台加载数据
        let fetchedData = self?.getRemoteData()
        
        DispatchQueue.main.async {
            guard let self = self, !self.isControllerCancelled else {
                // 控制器已销毁,直接返回
                return
            }
            // 只有控制器有效时才更新CollectionView
            self.collectionView.reloadData()
        }
    }
}

这样可以避免控制器已经被销毁了,还在执行CollectionView的刷新操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:47:43