UICollectionViewDiffableDataSource - Crash when having equal items with different hash
Asked Answered
C

1

7

I am using UICollectionViewDiffableDataSource to fill UICollectionView with data. My understanding is that DiffableDataSource compares items by using == and then if items are equal it compares hash values to see if something changed.

But according to the error I am getting this isn't the case.

Diffable data source detected item identifiers that are equal but have different hash values. Two identifiers which compare as equal must return the same hash value. You must fix this in the Hashable (Swift) or hash property (Objective-C) implementation for the type of these identifiers

In my case I have item that I compare against uniqueID and hashValue is determined by value that user entered. What is the point of using == and hashValue if they can't be different?

Classicism answered 9/2, 2022 at 8:51 Comment(0)
B
0

workaround: equaltable by hashValue and uniqueID to avoid equal but have different hash values crash.

static func == (lhs: Item, rhs: Item) -> Bool {
   lhs.hashValue == rhs.hashValue && lhs.id == rhs.id
}

Maybe not a perfect solution. In my case, I only need == for moving animation, so I send changed value by notification when only one item changes and needs moving, and replacing item after animation:

dataSource.apply(snapshot, animatingDifferences: true) { [weak self] in
    guard let self else { return }
    snapshot.insertItems([newItem], beforeItem: item)
    snapshot.deleteItems([item])
    snapshot.reconfigureItems([newItem])
    dataSource.apply(snapshot, animatingDifferences: false)
}

Couldn't agree more with 'What is the point of using == and hashValue if they can't be different' :)

Blennioid answered 19/12, 2023 at 9:26 Comment(4)
It is mandatory that any two objects that are considered equal (via ==) must also have the same hash value. Or looked at another way, two objects with different hash values can't be considered equal. But note that two objects with the same hash value do not have to be equal. They can be unequal. So your last line is based on a false assumption because == and hashValue can be different.Monteiro
@Monteiro Yes, you are right, so I post this answer as a workaround to avoid crash in production. and lhs.hashValue == rhs.hashValue has changed to lhs.hashValue == rhs.hashValue && lhs.id == rhs.idBlennioid
There's no reason to base == on both id and hashValue. You would base hashValue on id and then you would base == on id and possibly other properties.Monteiro
@Monteiro But NSDiffableDataSourceSnapshot will not update cell when other property changed if Item is a struct.Blennioid

© 2022 - 2024 — McMap. All rights reserved.