AirXygène
AirXygène

Reputation: 2919

How to avoid uicollectionview deselect all items when new snapshot is applied?

When I call dataSource?.apply(snapshot, animatingDifferences: true), the related UICollectionView deselects all cells.

This is a problem when receiving new data in the background as, when this change is commited, the user sees its current selection disappear.

How to avoid deselection of all collection items when apply(snapshot: animatingDifferences) is called ?

Upvotes: 1

Views: 379

Answers (1)

AirXygène
AirXygène

Reputation: 2919

After some digging, I found the root of the problem, and it lies inside Apple's code. At a minimum, I'd call that an "undocumented feature", some might say it's a bug.

When a snapshot is applied, the behavior of the UICollectionViewDiffableDataSource differs, whether the ItemIdentifierType is a value-type or a reference-type.

Of course, your ItemIdentifierType must conform to Hashable, but when calling apply(snapshot, animatingDifferences: true):

  • If ItemIdentifierType is a value-type (struct), then, its ==and hash functions are called, in order to compare the items of the newly received snapshot to the items of the currently shown snapshot, which allows to find the diff, animate differenes, and keep the selection if any (which was the original problem I asked help for).
  • If ItemIdentifierType is a reference-type (class), then, its ==and hash function are not called, which means that the items of the new snapshot and the currently shown snapshot are compare with bare reference equality (are pointers equal). As a consequence, if you have built your items "from scratch" with new instances having the same hash, then the comparison is always false, and you don't get the animations, and you loose the selection.

One easy work-around in this situation is to encapsulate your reference-type into a struct, which will forward == and hash to the class ones, and use this struct as the ItemIdentifierType

Upvotes: 1

Related Questions