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

水平UICollectionView无数据时刷新父视图出现崩溃该如何解决?

崩溃根本原因

触发崩溃的核心是UICollectionView数据源更新与布局调整的时序不一致,结合你的代码逻辑具体原因如下:

  • 你在API请求返回更新shownStations、hiddenStations数据源后,没有先调用reloadData()同步collectionView的内部计数,就先修改了collectionView的frame。修改frame会触发collectionView的内部布局刷新,此时系统会尝试调整滚动位置适配新的frame,而collectionView内部还保留着旧数据的item计数、滚动位置信息,和最新的空数据源不匹配。
  • 当数据源最终返回0个item时,系统内部布局逻辑尝试滚动到之前的有效item位置(比如之前的第0个item),但当前section下已经没有任何item,就触发了数组越界的内部一致性异常。
  • 额外诱因:用设置零宽高frame的方式隐藏视图,会强制触发不必要的布局计算,相比直接用isHidden属性隐藏更容易触发此类布局时序问题。
修复方案

按优先级提供以下修复方式,建议同时应用前两项:

  1. 调整数据源更新与刷新的时序
    先调用reloadData()同步collectionView的内部状态,再修改frame或者隐藏视图,代码示例:
// 先刷新数据源状态
self.stationCollectionView?.reloadData()
// 再调整布局/显隐
if self.shownStations.isEmpty {  
    self.stationCollectionView?.isHidden = true
    // 不需要再设零frame,用isHidden性能更好也不会触发布局
} else {
    self.stationCollectionView?.isHidden = false
    self.stationCollectionView?.frame = CGRect(x: 0, y: 0, width: 414, height: 150)
}
  1. 在numberOfItems数据源方法中加兜底判断,避免返回异常计数
    当shownStations为空时,不管hiddenStations是否有值,都直接返回0,避免出现数据源为空但返回1个item的异常情况(防止cellForItem时也出现越界):
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    if self.shownStations.isEmpty {
        return 0
    }
    if !self.hiddenStations.isEmpty {
        return shownStations.count + 1
    } else {
        return shownStations.count
    }
}
  1. 可选优化:如果需要保留零frame的设置,可在显隐时先清空collectionView的滚动偏移
    修改frame前先把contentOffset置为零,避免系统尝试滚动到无效位置:
if self.shownStations.isEmpty {  
    self.stationCollectionView?.contentOffset = .zero
    self.stationCollectionView?.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
} else {
    self.stationCollectionView?.frame = CGRect(x: 0, y: 0, width: 414, height: 150)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 23:45:06