web-dev-qa-db-ja.com

iOS 13でのTableViewエラーの差分データソース:移動の関連付けに一貫性がない

現在のUITableviewをiOS 13 UITableViewDiffableDataSourceが提供するdiffableデータソースに更新しています。

カスタムオブジェクトを含む配列があります(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:、例外が発生します。

***キャッチされない例外 'NSInvalidArgumentException'によりアプリを終了します、理由: '移動の関連付けが矛盾しています'

どういう意味ですか?どうすれば解決できますか?

10
Fabiosoft

更新された回答

私はこれに関して私が提起したバグへの応答を得るのに十分幸運でした。私のモデルオブジェクトには、不正なハッシュおよび等価チェックがあったことがわかりました。

My Swift構造体はHashableに準拠しましたが、Equatableのカスタム実装を提供しました。これにより、IDプロパティを比較して等しいかどうかを判断するだけでした。これは、2つのオブジェクトを等しいと見なすことが可能だったが、ハッシュが異なるため、差分アルゴリズムが混乱します。

それを解決するために、Equatableのカスタム実装を削除し、合成バージョンを使用しました。

あなたは質問の中で、Swiftの_==_に類似したisEqual、ObjCを実装すると述べていますが、すべての場合においてhash実装と一致するisEqual実装を提供していない可能性があります。


元の回答(この場合はおそらく正しくありませんが、キューが問題である場合は引き続き役立つ場合があります)

これがあなたと同じ問題かどうかはわかりませんが、私の場合は、異なるキューから呼び出されているapplySnapshotメソッドが原因でした。

Advanced Data Sources WWDCセッションでは、applySnapshotはバックグラウンドキューで排他的に呼び出す必要があると述べましたORメインキューですが、両方からは呼び出さないでください。 Advanced Data Sources WWDC 2019 =-32:00

Advanced Data Sources WWDC 2019

私の場合、データソースの変更に対応するためにCombineパブリッシャーを使用しており、そのパブリッシャーはメインスレッドまたはバックグラウンドスレッドで値を送信することがありました。私の問題を解決するために、チェーンに.receive(on: RunLoop.Main)を追加しました。

あなたの場合、多分あなたはそれを実行したいキューを使って_updateTableViewAnimated:_への呼び出しを行うものを_dispatch_async_呼び出しでラップすることができます(メインかバックグラウンドかにかかわらず)。

6
Jasarien

Jasarienの有益な回答に加えて、UICollectionViewDiffableDataSourceはハッシュ可能を使用してデータソース内のアイテムを区別することを覚えておく必要があります

モデルが構造体であり、データソースモデルに2つのアイテムがあり、それらがまったく同じ値である場合、Hashableプロトコルは同じハッシュ値を生成します。

また、Equatableプロトコルはtrueを返します! 、これはUICollectionViewDiffableDataSourceを混乱させます

ソリューション

  • データソースに重複がないことを確認してください
  • 重複を避けられず、Equatableのブレーキングを気にしない場合は、データソースにランダムな値を追加することをお勧めしますが、生成された値は偶然に等しくなる可能性があるため、お勧めしません。 Documentionsで*低い確率ですが、発生する可能性があります*

範囲のサイズと範囲によっては、一部の具体的な値が他の値よりも頻繁に表される場合があります。

2
Mostfa Essam