Invalid parameter not satisfying: initialSnapshot.numberOfSections == initialSections.count

328 views Asked by At

Working on a new project, our team decided to use UICollectionViewDiffableDataSource to handle our collection views. It works fine, but we're getting (infrequent) crashes logged via an online tool with the message Invalid parameter not satisfying: initialSnapshot.numberOfSections == initialSections.count. We can't seem to reproduce this locally.

The crash occurs at the point where we update the data source with new data, specifically at dataSource.apply(snapshot). We're unsure as to how this could happen, as the data is always created the same.

Specifically, the unit working on this one view decided to forgo the creation of a section model and instead decided to use an Int as section identifiers, because they didn't want to use sections, just display items. That's one thing I hadn't seen before, but an Int satisfies the requirements for identifiers, so the code does compile correctly.

Here is the code:

Collection View and Data Source creation

These variables are inside the class of a UIView which is programmatically created.

var collectionView = UICollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
lazy var dataSource = UICollectionViewDiffableDataSource<Int, URL>(collectionView: collectionView, cellProvider: provideCell(_:indexPath:item:))

Updating the Datasource

func updateUI() {
    var snapshot = dataSource.snapshot()
    snapshot.deleteAllItems()
    snapshot.appendSections([0])
    
    if let urls = viewModel?.imageUrls {
        snapshot.appendItems(urls)
    }

    dataSource.apply(snapshot)
}

In all (production) cases I have tested, viewModel?.imageUrls is empty on the first call, then contains items on the second call and all calls after that. The number of items usually doesn't change.

I have thought about not using dataSource.snapshot() and instead creating a new one, then I also wouldn't have to call deleteAllItems() every time. But I don't want to just push this as the solution when I can't be sure whether this really fixes the issue.

Has anyone encountered an issue like this before? Is it correct to use an Int as the section identifier? What could be other causes of the crash?

1

There are 1 answers

0
Viktor Gavrilov On

My guess is that you delete only items and each time you add an additional section to your snapshot, which causes an error. So if your Snapshot already has a "0" section, you do not need to add a new one each time.

In my projects I create a new snapshot every time:

var snapshot = NSDiffableDataSourceSnapshot<Int, URL>()
snapshot.appendSections([0])
if let urls = viewModel?.imageUrls {
    snapshot.appendItems(urls, toSection: 0)
}
customDataSource.apply(snapshot, animatingDifferences: animate)

The same approach is used in WWDC videos.