Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS13 DiffableDataSource Invalid parameter not satisfying: indexPath || ignoreInvalidItems

I'm converting my collection view to new iOS13 UICollectionViewDiffableDataSource... so I need to update cell information on demand.

Here is my code:

let snap = self.diffDataSouce.snapshot
snap?.reloadItems(withIdentifiers: [itemToUpdate]) //reload cell info
self.diffDataSouce.apply(snap, animatingDifferences: true)

But I get Invalid parameter not satisfying: indexPath || ignoreInvalidItems ...why? My current snap contains itemToUpdate and also my array of models...

I think it's because snap.indexOfItemIdentifier(itemToUpdate) returns not found (NSNotFound)...but that's should be impossible according data model.

Have you some hints?

like image 743
Fabiosoft Avatar asked Nov 25 '19 10:11

Fabiosoft


3 Answers

Your data model has to conform to Hashable and Equatable, so that the diffing algorithm can track changes between snapshots.

If there is an issue with a collision between two objects, or you have implemented either of those protocols in such a way as to allow for two objects to appear equal to the diffing algorithm, you will get a runtime assert exception.

I'd track down exactly how your model object have inherited or implemented those protocols.

like image 132
oflannabhra Avatar answered Oct 06 '22 19:10

oflannabhra


Have you implemented the static func == for your model? I had a similar issue using structs where equality is evaluated among all properties

like image 24
emix Avatar answered Oct 06 '22 18:10

emix


For my case, reloading a hashable item was the problem. Instead I should have deleted hashable item and inserted anew. Following are the specifics.

My diffable ItemIdentifierType was of AnyHashable type as in:

var dataSource: UICollectionViewDiffableDataSource<AHashableEnum, AnyHashable>!

And whenever I wanted to reload a single item like the author of this exchange, I was experiencing the crash:

var currentSnapshot = dataSource.snapshot()
currentSnapshot.reloadItems([hashableItemThatGotUpdated])
dataSource.apply(currentSnapshot, animatingDifferences: true)

I realized that since ItemIdentifierType is of AnyHashable type, reloading an item is not permitted if its hashvalue has changed. Because the hash value of the new item does not exist in the current snapshot and therefore is not reloadable. Instead I should have deleted the old item from the current snapshot and inserted the new Hashable identifer instead:

var currentSnapshot = dataSource.snapshot()
currentSnapshot.insertItems(identifiers: [NewHashableItemIdentifier], beforeItem: OldHashableItemIdentifier)
currentSnapshot.deleteItems(identifiers: [OldHashableItemIdentifier])
dataSource.apply(currentSnapshot, animatingDifferences: true)
like image 38
deniz Avatar answered Oct 06 '22 19:10

deniz