UICollectionView数据更新后Cell未同步更新问题求助
问题解决:UICollectionView切换星标后原Cell状态未更新
核心问题原因
- Object的Hashable实现不完整:当前仅用
name判断对象相等和计算哈希值,isStarredObject变化时,DiffableDataSource无法识别对象已更新,因此不会刷新对应Cell。 - Cell未在数据更新时同步按钮状态:
object属性赋值后仅更新标签,未调用updateButton同步星标状态。 - 快照刷新逻辑冗余:手动处理差异的逻辑存在疏漏,未确保所有对象的星标状态被正确同步到快照。
解决方案及代码修改
1. 修复Object的Hashable实现
将isStarredObject纳入相等判断和哈希计算,确保状态变化能被DiffableDataSource识别:
extension Object: Hashable { static func == (lhs: Object, rhs: Object) -> Bool { return lhs.name == rhs.name && lhs.isStarredObject == rhs.isStarredObject } func hash(into hasher: inout Hasher) { hasher.combine(name) hasher.combine(isStarredObject) } }
2. 完善Cell的object属性didSet方法
每次赋值object后立即同步按钮状态:
var object: Object? { didSet { if let object = object { self.label.text = object.name self.updateButton() // 新增:同步按钮状态 } } }
3. 简化refreshSnapshot逻辑
直接生成排序后的数组,利用DiffableDataSource自动处理差异:
func refreshSnapshot() { guard let dataSource = dataSource else { return } // 生成排序后的数组:星标对象在前,其余按原顺序 let starred = objects.filter { $0.isStarredObject } let unstarred = objects.filter { !$0.isStarredObject } let sortedObjects = starred + unstarred var snapshot = NSDiffableDataSourceSnapshot<Int, Object>() snapshot.appendSections([0]) snapshot.appendItems(sortedObjects) dataSource.apply(snapshot, animatingDifferences: true) }
4. 优化Cell的updateButton方法
移除不必要的delegate判断,仅依赖object状态:
func updateButton() { guard let object = object else { print("No object assigned to cell") return } if object.isStarredObject { let newImage = UIImage(systemName: "star.fill", withConfiguration: imageConfig) self.button.setImage(newImage, for: .normal) self.button.isEnabled = false } else { let newImage = UIImage(systemName: "star", withConfiguration: imageConfig) self.button.setImage(newImage, for: .normal) self.button.isEnabled = true } }
5. 移除自定义的applyDifferences扩展
DiffableDataSource会自动计算并应用快照差异,无需手动处理,可删除该扩展:
// 移除以下扩展 // extension NSDiffableDataSourceSectionSnapshot { // mutating func applyDifferences(newItems: [ItemIdentifierType]) { // ... // } // }
验证效果
修改后,点击新的空心星Cell时:
- 原星标对象的
isStarredObject被设为false - 新对象的
isStarredObject被设为true - 快照刷新时,DiffableDataSource识别到对象状态变化,自动刷新所有受影响的Cell
- 排序逻辑正常,星标对象始终排在首位
内容的提问来源于stack exchange,提问作者Moses Harding
相关产品推荐
相关产品推荐

