I am getting an exception when doing a search on multiple section. It occurs when applying a snapshot on the datasource.

Background: I have (pre-defined) sections, and each section has a collection of items. Sections won't appear in the viewController if there are no items in section. Items are added by a function of the app. Once an item is added in one of the section, datasource update is called and will show the section with the item added.

Problem: Encountering this issue when trying to search for a non-existent item twice. To reproduce, you can enter a non-existent item, then delete the search string via a backspace, then input a non-existing item again, then error will be thrown on the dataSource.apply().

Hoping someone can help. TIA!

Here is the code:

    func updateData(on searchItem: String = "") {
        //create a snapshot that will be used by the datasource to apply the diff changes
        snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        
        Manager.shared.getAllSections().forEach { section in
            
            let items = section.items
            
            //if search string is empty, we just assign the items of the section, 
            //else we filter it based on the searchItem
            var filteredItems = searchItem.isEmpty ? items :
                items.filter { $0.itemName.lowercased().contains(searchItem.lowercased()) }
            
            //if theres no items filtered, we ain't appending any section and items
            if filteredItems.count > 0 {
                snapshot.appendSections([section])
                snapshot.appendItems(filteredItems)
            }
        }
        
        //when calling apply, i get the exception when calling apply on dataSource
        dataSource.apply(snapshot, animatingDifferences: false)
    }

    //Here is the updateSearchResults delegate method triggered when typing something in the search bar
    func updateSearchResults(for searchController: UISearchController) {
        guard let searchedItem = searchController.searchBar.text, !searchedItem.isEmpty else {
            updateData()
            return
        }
        
        updateData(on: searchedItem)
    }
2

There are 2 answers

1
bze12 On

ok so I think this is some type of internal bug in diffable data source where it doesn't like when you have 0 sections in your collection view, but the workaround I figured out was to just add a dummy section and hide the section header (if you have one).

in your updateData() method you could add:

if snapshot.numberOfItems == 0 {
    snapshot.appendSections([YourSection(name: "dummy")])
}

Then if you're using a section header, give that dummy section some identifiable variable that you can use to hide the header. When dequeuing a supplementary view (header), check if the name == "dummy" then hide the header if so.

It's a hack, but it ends up looking the exact same and you don't have to deal with ugly empty sections being displayed.

0
rgkobashi On

My understanding is that that happens when the compositional layout is trying to resolve layout for a section that doesn't exist in the data source.

In my case I was using UICollectionViewCompositionalLayout(sectionProvider:) which was returning old sections when my data source was returning the correct ones but different.

How I fixed it was invalidating the layout: collectionView.collectionViewLayout.invalidateLayout()