iOS 13 上 TableView 错误的可区分数据源:移动关联不一致
Diffable data source for TableView error on iOS 13: Inconsistent associations for moves
我正在将当前的 UITableview 更新为 iOS 13 UITableViewDiffableDataSource
.
提供的可区分数据源
我有一个带有自定义对象的数组(实现 isEqual: 方法)。在 viewWillAppear 上,我从磁盘加载数据并调用申请快照。
-(void)updateTableViewAnimated:(BOOL)animated API_AVAILABLE(ios(13.0)){
NSDiffableDataSourceSnapshot *snapshot = [[NSDiffableDataSourceSnapshot alloc]init];
[snapshot appendSectionsWithIdentifiers:@[@"sectionTitle"]];
[snapshot appendItemsWithIdentifiers:self.playlists];
[self.diffDataSource applySnapshot:snapshot animatingDifferences:animated];
}
一切都加载。但是当尝试从数组中删除一个项目并再次调用时 updateTableViewAnimated:
,我得到一个异常。
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Inconsistent associations for moves'
这是什么意思?
我该如何解决?
更新答案
我很幸运能够对我提出的有关此问题的错误做出回应。事实证明,我的模型 object 的哈希和相等性检查不正确。
我的 swift 结构符合 Hashable,但提供了 Equatable 的自定义实现,因此我只比较 ID 属性 以确定是否相等。这意味着两个 object 可能被认为是相等的,但具有不同的哈希值,这会混淆差异算法。
为了解决这个问题,我简单地删除了 Equatable 的自定义实现,并使用了合成版本。
你在问题中声明你实现了 isEqual
,ObjC,类似于 Swift 的 ==
,但你可能没有提供 hash
在所有情况下都与您的 isEqual
实施一致的实施。
原始答案(对于这种情况可能不正确,但如果队列有问题,可能仍然有用)
我不知道这是否与您遇到的问题相同,但就我而言,这是由从不同队列调用 applySnapshot
方法引起的。
高级数据源 WWDC session 提到 applySnapshot
必须在后台队列或主队列上独占调用,但不要从两者调用。 Advanced Data Sources WWDC 2019 - 32:00
在我的例子中,我使用 Combine 发布者来响应我的数据源上的更改,并且该发布者有时会在主线程或后台线程上发送值。为了解决我的问题,我将 .receive(on: RunLoop.Main)
添加到链中。
在你的情况下,也许你可以在 dispatch_async
调用中包装任何调用 updateTableViewAnimated:
的东西,使用你希望它在 运行 上的队列(主要或背景)。
添加到 Jasarien 信息性答案中,
你需要记住 UICollectionViewDiffableDataSource
使用 hashable 来区分数据源中的项目
如果您的模型是一个结构,并且您的数据源模型中有两个项目恰好具有完全相同的值,Hashable
协议将为它们生成相同的哈希值。
另外 Equatable
协议将 return 成真! , 这会混淆
UICollectionViewDiffableDataSource
解决方案
- 确保您的数据源没有任何重复项
- 如果您无法避免重复,并且您不介意刹车
Equatable
,您可能希望在数据源中添加随机值,但不建议这样做,因为生成的值可能在任何时候都相等巧合,如文档中所述
*低概率,但它可能会发生 *
Depending on the size and span of range, some concrete values may be represented more frequently than others.
我正在将当前的 UITableview 更新为 iOS 13 UITableViewDiffableDataSource
.
我有一个带有自定义对象的数组(实现 isEqual: 方法)。在 viewWillAppear 上,我从磁盘加载数据并调用申请快照。
-(void)updateTableViewAnimated:(BOOL)animated API_AVAILABLE(ios(13.0)){
NSDiffableDataSourceSnapshot *snapshot = [[NSDiffableDataSourceSnapshot alloc]init];
[snapshot appendSectionsWithIdentifiers:@[@"sectionTitle"]];
[snapshot appendItemsWithIdentifiers:self.playlists];
[self.diffDataSource applySnapshot:snapshot animatingDifferences:animated];
}
一切都加载。但是当尝试从数组中删除一个项目并再次调用时 updateTableViewAnimated:
,我得到一个异常。
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Inconsistent associations for moves'
这是什么意思? 我该如何解决?
更新答案
我很幸运能够对我提出的有关此问题的错误做出回应。事实证明,我的模型 object 的哈希和相等性检查不正确。
我的 swift 结构符合 Hashable,但提供了 Equatable 的自定义实现,因此我只比较 ID 属性 以确定是否相等。这意味着两个 object 可能被认为是相等的,但具有不同的哈希值,这会混淆差异算法。
为了解决这个问题,我简单地删除了 Equatable 的自定义实现,并使用了合成版本。
你在问题中声明你实现了 isEqual
,ObjC,类似于 Swift 的 ==
,但你可能没有提供 hash
在所有情况下都与您的 isEqual
实施一致的实施。
原始答案(对于这种情况可能不正确,但如果队列有问题,可能仍然有用)
我不知道这是否与您遇到的问题相同,但就我而言,这是由从不同队列调用 applySnapshot
方法引起的。
高级数据源 WWDC session 提到 applySnapshot
必须在后台队列或主队列上独占调用,但不要从两者调用。 Advanced Data Sources WWDC 2019 - 32:00
在我的例子中,我使用 Combine 发布者来响应我的数据源上的更改,并且该发布者有时会在主线程或后台线程上发送值。为了解决我的问题,我将 .receive(on: RunLoop.Main)
添加到链中。
在你的情况下,也许你可以在 dispatch_async
调用中包装任何调用 updateTableViewAnimated:
的东西,使用你希望它在 运行 上的队列(主要或背景)。
添加到 Jasarien 信息性答案中,
你需要记住 UICollectionViewDiffableDataSource
使用 hashable 来区分数据源中的项目
如果您的模型是一个结构,并且您的数据源模型中有两个项目恰好具有完全相同的值,Hashable
协议将为它们生成相同的哈希值。
另外 Equatable
协议将 return 成真! , 这会混淆
UICollectionViewDiffableDataSource
解决方案
- 确保您的数据源没有任何重复项
- 如果您无法避免重复,并且您不介意刹车
Equatable
,您可能希望在数据源中添加随机值,但不建议这样做,因为生成的值可能在任何时候都相等巧合,如文档中所述 *低概率,但它可能会发生 *
Depending on the size and span of range, some concrete values may be represented more frequently than others.