使用NSDiffableDataSourceSectionSnapshot时点击cell更新section counter不生效如何解决
问题核心原因
1. 值类型修改未同步到本地数据源
TestParent是结构体(值类型),你从DiffableDataSource快照中取出的section是值拷贝,修改局部section.counter不会同步到你自己维护的parents数据源数组,同时修改后的实例和快照中原有section的Hash值不同,reloadSections无法匹配到目标section,不会触发刷新。
2. Section标识的Hash计算包含可变属性
默认自动合成的Hashable实现会把counter这类可变属性纳入Hash计算,同一个逻辑section修改counter后会被DiffableDataSource判定为不同section,无法正确识别更新。
解决方案
第一步:修改TestParent的Hash规则,仅用唯一标识匹配
struct TestParent: Hashable { // 新增唯一标识,区分不同section let id = UUID() var title = String() var counter = 0 var children = [TestChildren]() // 仅用id判断是否为同一个section static func == (lhs: TestParent, rhs: TestParent) -> Bool { lhs.id == rhs.id } func hash(into hasher: inout Hasher) { hasher.combine(id) } }
第二步:修改点击事件逻辑,先更新本地数据源再刷新
如果你的sectionHeader配置是直接从parents数组按索引读取counter值,用简化版代码即可:
fileprivate func check(indexPath: IndexPath) { guard let children = self.dataSource?.itemIdentifier(for: indexPath) as? TestChildren else { return } guard let oldSection = self.dataSource?.snapshot().sectionIdentifier(containingItem: children) as? TestParent else { return } // 找到本地数据源中对应的parent,更新counter guard let targetIndex = parents.firstIndex(where: { $0.id == oldSection.id }) else { return } parents[targetIndex].counter += 1 // 直接刷新对应section var mainSnapshot = dataSource?.snapshot() mainSnapshot?.reloadSections([oldSection]) dataSource?.apply(mainSnapshot!, animatingDifferences: false) }
如果你需要快照中存储的section实例本身包含最新的counter值,用完整更新逻辑:
fileprivate func check(indexPath: IndexPath) { guard let children = self.dataSource?.itemIdentifier(for: indexPath) as? TestChildren else { return } guard let oldSection = self.dataSource?.snapshot().sectionIdentifier(containingItem: children) as? TestParent else { return } guard let targetIndex = parents.firstIndex(where: { $0.id == oldSection.id }) else { return } parents[targetIndex].counter += 1 let updatedSection = parents[targetIndex] // 替换快照中的旧section实例 var mainSnapshot = dataSource?.snapshot() mainSnapshot?.insertSections([updatedSection], afterSection: oldSection) mainSnapshot?.deleteSections([oldSection]) dataSource?.apply(mainSnapshot!, animatingDifferences: false) // 重新应用该section的子项快照 dataSource?.apply(parentSnapshot(updatedSection), to: updatedSection) }
内容的提问来源于stack exchange,提问作者Foster
相关产品推荐
相关产品推荐

