iosswiftcore-datauicollectionviewcompositionallayoutnsdiffabledatasourcesnapshot

How to deal with inconsistent behavior when change snapshot animatedDifferences value?


I'll start with explanation how things suppose to work:

I have collection view with compositional layout and diffable data source.

Cells are representing tasks, which user can click on and set as done for today, cells have different appearance depending on if its set as done or not and cell checks CoreData to find out is it done or not.

Now i tried to implement an idea that tasks done for a day go to the bottom of the view so at the top are only those which still have to be done. To do that i set up sort descriptor for my fetch request.

Till that moment everything works as expected but i wanted to make this cell moving down animated, so i changed dataSource.apply(snapshot, animatingDifferences: false) to true

Now its animated but cells don't change appearance when set as done.

Here is my setupSnapshot method():

func setupSnapshot() {
    snapshot = NSDiffableDataSourceSnapshot<Section, Task>()
    snapshot.appendSections([.main])
    snapshot.appendItems(fetchedResultsController.fetchedObjects ?? [])
    dataSource.apply(snapshot, animatingDifferences: true)   
}

Have a look: animatingDifferences: false(left) and true(right)

animatingDifferences: false animatingDifferences: true

As a summary, my goal is to have:

1) animated cells and 2) changed appearance when set as done. It seems that with animatingDifferences: false i can have only goal 2 and with animatingDifferences: true can have only goal 1

I've tried research this topic already and found something about applying snapshot twice, once for sections and once for items but it didn't make any difference.

Anyone can point out what am i missing here?


Solution

  • After further investigation and according to comments from here:

    How to get a diffable snapshot from an NSFetchResultsController in iOS 13?

    there is a difference in behavior in apply(snapshot: animatingDifferences:) when its parameter animatingDifferences has different value.

    Seems like with animatingDifferences: false there is reloadData() going on under the hood which is not happening with animatingDifferences: true, at least according to those comments and its consistent with my experience.

    Therefore solution for my code is adjusting setupSnapshot to:

    func setupSnapshot(animated: Bool) {
          snapshot = NSDiffableDataSourceSnapshot<Section, Task>()
          snapshot.appendSections([.main])
          snapshot.appendItems(fetchedResultsController.fetchedObjects ?? [])   
          dataSource.apply(snapshot, animatingDifferences: animated) {
             if animated {
                self.collectionView.reloadData()
             }
          }
    }