現在の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'によりアプリを終了します、理由: '移動の関連付けが矛盾しています'
どういう意味ですか?どうすれば解決できますか?
私はこれに関して私が提起したバグへの応答を得るのに十分幸運でした。私のモデルオブジェクトには、不正なハッシュおよび等価チェックがあったことがわかりました。
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
私の場合、データソースの変更に対応するためにCombineパブリッシャーを使用しており、そのパブリッシャーはメインスレッドまたはバックグラウンドスレッドで値を送信することがありました。私の問題を解決するために、チェーンに.receive(on: RunLoop.Main)
を追加しました。
あなたの場合、多分あなたはそれを実行したいキューを使って_updateTableViewAnimated:
_への呼び出しを行うものを_dispatch_async
_呼び出しでラップすることができます(メインかバックグラウンドかにかかわらず)。
Jasarienの有益な回答に加えて、UICollectionViewDiffableDataSource
はハッシュ可能を使用してデータソース内のアイテムを区別することを覚えておく必要があります
モデルが構造体であり、データソースモデルに2つのアイテムがあり、それらがまったく同じ値である場合、Hashable
プロトコルは同じハッシュ値を生成します。
また、Equatable
プロトコルはtrueを返します! 、これはUICollectionViewDiffableDataSource
を混乱させます
ソリューション
Equatable
のブレーキングを気にしない場合は、データソースにランダムな値を追加することをお勧めしますが、生成された値は偶然に等しくなる可能性があるため、お勧めしません。 Documentionsで*低い確率ですが、発生する可能性があります*範囲のサイズと範囲によっては、一部の具体的な値が他の値よりも頻繁に表される場合があります。