我的订阅触发得太频繁,导致我的代码调用 snapshot.apply() 的次数超出了必要的范围。虽然我同意我应该努力避免这种情况,但所有单元格都会重新生成这一事实表明我从根本上以某种方式滥用了我的 UICollectionViewDiffableDataSource。
我检查了,唯一调用数据源的代码如下
typealias DataSource = UICollectionViewDiffableDataSource<Section, CellModel>
typealias Snapshot = NSDiffableDataSourceSnapshot<Section, CellModel>
func setupDataSource() -> DataSource {
let dataSource = DataSource(
collectionView: collectionView,
cellProvider: { collectionView, indexPath, model ->
UICollectionViewCell? in
let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: "CollabPageCollectionViewCell",
for: indexPath) as? CollabPageCollectionViewCell
cell?.pageModel = model
return cell
})
return dataSource
}
func callAfterUpdatingCollectionModels() {
if memory.count == collectionPages.count {
for i in 0..<memory.count {
if memory[i] != collectionModels[i] {
print("EQUATABLE FAIL AT \(i)")
}
if memory[i].hashValue != collectionModels[i].hashValue {
print("EQUATABLE FAIL AT \(i)")
}
}
} else {
print("This print should only be seen once ")
}
memory = collectionModels
guard self.collectionView.dataSource != nil else { return }
var snapshot = Snapshot()
snapshot.appendSections([.main])
snapshot.appendItems(collectionModels)
self.dataSource.apply(snapshot, animatingDifferences: true)
}
onOverZealousModelSubscription {
// Rebuild collectionModels to be exactly the same thing it used to be
callAfterUpdatingCollectionModels()
}
然后是这里的模型对象
class CellModel: Hashable, Equatable, ObservableObject {
static func == (lhs: CellModel, rhs: CellModel) -> Bool {
return lhs.id == rhs.id && lhs.aspect == rhs.aspect && lhs.delegate === rhs.delegate && lhs.shouldBeHighlighted == rhs.shouldBeHighlighted
}
let id: UUID
let aspect: CGFloat
private(set) weak var delegate: CellModelDelegate?
@Published var shouldBeHighlighted: Bool
func hash(into hasher: inout Hasher) {
id.hash(into: &hasher)
aspect.hash(into: &hasher)
shouldBeHighlighted.hash(into: &hasher)
}
}
那么什么给出了呢?对我来说,我已经验证了所有模型对象的哈希值和计数是否相等。 dequeueReusableCell 的回溯验证其来自 self.dataSource.apply 但这些单元格仍然在尝试更新。
我确实创建了一个最小可重现的案例,但据我所知,没有好的方法可以在此处上传该项目。
过了一段时间就明白了。事情是这样的。因为实现 Equatable 和 Hashable 的 UIDiffableDataSource 的实现是无效的,即使文档没有这样建议。
使这个对象实现 NSObject 并向目标 c 公开 equatable 和 hashable 就可以了。此处的答案对此进行了更详细的说明。 https://stackoverflow.com/a/69994675/3833632