为什么UICollectionViewDiffableDataSource无数据变更时全量重加载所有cell
问题原因
这个现象不是系统Bug,是UICollectionViewDiffableDataSource的设计行为,和使用方式共同导致的:
- 当
animatingDifferences参数设为false时,DiffableDataSource会主动跳过差异计算逻辑,直接调用UICollectionView的reloadData()方法全量刷新所有cell,无论新旧快照的数据是否完全一致。这是系统为无动效全量刷新场景设计的快速路径,不会做增量变更校验。 - 当
animatingDifferences参数设为true时,系统会完整比对新旧快照的Hash值差异,只有真正发生增删改的条目才会触发cell的重新配置,因此相同数据重复apply时不会刷新cell。
优化方案
如果需要保留无动效的刷新行为,又要避免无意义的全量cell重加载,可以采用以下两种方案二选一:
方案1:快照变更校验(兼容所有iOS版本)
每次构建新快照后先和当前已有快照比对,只有快照确实发生变化时才执行apply操作:
func updateSnapshot(animatingChange: Bool = false) { let currentSnapshot = dataSource.snapshot() var newSnapshot = NSDiffableDataSourceSnapshot<Section, Item>() newSnapshot.appendSections([.all]) newSnapshot.appendItems(self.items, toSection: .all) // 数据无变更直接跳过apply,避免全量刷新 guard newSnapshot != currentSnapshot else { return } self.dataSource.apply(newSnapshot, animatingDifferences: animatingChange) }
方案2:无动画执行差异更新(iOS 13+兼容)
如果不需要刷新动效,又需要系统自动做差异校验,可以将animatingDifferences设为true后放在无动画块中执行:
func updateSnapshot(animatingChange: Bool = false) { var snapshot = NSDiffableDataSourceSnapshot<Section, Item>() snapshot.appendSections([.all]) snapshot.appendItems(self.items, toSection: .all) if animatingChange { dataSource.apply(snapshot, animatingDifferences: true) } else { UIView.performWithoutAnimation { dataSource.apply(snapshot, animatingDifferences: true) } } }
两种方案都可以避免相同数据重复apply时的全量cell重加载问题。
内容的提问来源于stack exchange,提问作者Logan Shire
相关产品推荐
相关产品推荐

