1

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)
    }
arvinq
  • 656
  • 6
  • 12
  • I'm getting the same issue in my own app. Are you clearing the snapshot for each search results update? – bze12 Jul 21 '20 at 02:53
  • Hey @bze12! Glad to know someone out there is having the same issue. I don't think I am clearing the snapshot anywhere. It's just that I am not appending anything in the snapshot if the filtered item is empty. That somehow causes the issue. If I append the section and items (even if the items are empty), there's no exception thrown. However, sections will show without any item, and I don't like that. Still figuring out how to solve this. how's yours. – arvinq Jul 22 '20 at 07:14
  • Yeah I'm pretty stumped rn, applying an empty snapshot to the collection view shouldn't cause a problem. sometimes my error will be "invalid section 2" instead of 0, however. – bze12 Jul 24 '20 at 00:23
  • same bro @bze12. I excluded the search for now as I want to release soon. Will just add that feature when I have the answers.. BTW I've posted the same question in the dev portal.. https://developer.apple.com/forums/thread/654739?login=true&page=1#622544022 It didn't solve mine but maybe applicable to your prob.. Oh and if you find something, just let me know. :) cheers. – arvinq Jul 24 '20 at 06:17
  • honestly i think it's an internal bug with the diffable data source api. For now I'm also just gonna do a workaround but this thing is really annoying me :/ – bze12 Jul 25 '20 at 04:21

2 Answers2

1

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.

bze12
  • 727
  • 8
  • 20
  • Hey mate. thanks for answering. :) yeah. I tried this approach, but when I try the search, sure, it does not display the supplementary view anymore because its hidden.. However, it will still display a space allocated for the cells. nevertheless, this is a good solution. +1 – arvinq Jul 27 '20 at 07:38
0

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()

rgkobashi
  • 2,551
  • 19
  • 25