NSDiffableDataSource - the cellProvider on my CollectionView Data Source is not being called?

987 Views Asked by At

I have a data source like so

   fileprivate func makeRecordsDataSource() -> RecordsDataSource {
        let dataSource = RecordsDataSource(
            collectionView: recordsCollectionView,
            cellProvider: { (collectionView, indexPath, recordItem) ->
              UICollectionViewCell? in
                switch recordItem.type {
                case .Rep:
                    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RepRecordCell.identifier, for: indexPath) as? RepRecordCell
                    cell!.configure(with: recordItem)
                    return cell
                case .Image:
                    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageRecordCell.identifier, for: indexPath) as? ImageRecordCell
                    cell!.configure(with: recordItem)
                    return cell
                case .Video:
                    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: VideoRecordCell.identifier, for: indexPath) as? VideoRecordCell
                    cell!.configure(with: recordItem)
                    return cell
                case .Text:
                    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TextRecordCell.identifier, for: indexPath) as? TextRecordCell
                    cell!.configure(with: recordItem)
                    return cell
                }
            })
        return dataSource
    }

In my view controller I have

private lazy var recordsDataSource = makeRecordsDataSource()

Then a function to apply a snapshot to my data source....

func applyRecordsSnapshot(days:[YearMonthDay]) {
    var snapshot = RecordsDataSourceSnapshot()
    snapshot.appendSections(days)
    var i = 0
    for ymd in days {
        sectionMap[ymd] = i
        snapshot.appendItems(ymd.recordItems,toSection: ymd)
        i += 1
    }
    recordsDataSource.apply(snapshot, animatingDifferences: false)
}

in the debugger, when I look at the snapshot.numberOfItems, I see 4, so there are 4 sections... But for some reason the closure cellProvider never gets called when I put breakpoints inside of it. Wouldn't it get called once for each cell in the snapshot?

2

There are 2 best solutions below

3
Shawn Throop On

I’ve been learning the diffable data source and cell providers APIs this week and from my experience, it looks like you’re doing things correctly.

I did notice that you’re using the traditional dequeueReusableCell(withReuseIdentifier:for:) method. In the past I’ve had similar issues with UITableView when I didn’t register my cell.

collectionView.register(RepRecordCell.self, forCellWithReuseIdentifier: RepRecordCell.identifier)

It’s a one-liner and often separate from cell creation so maybe you are doing this and just omitted that part of for clarity.

Cell Registration in iOS 14.0

In my projects I’ve been using the new UICollectionView.CellRegistration API and it’s much cleaner and all in one place. Plus, no more need for reuseIdentifiers, pre-registration, and optional casting. Here’s how I configure my collectionView and dataSource:

let makeItemCell = UICollectionView.CellRegistration<UICollectionViewCell, Item> { cell, indexPath, item in
    cell.contentConfiguration = UIHostingConfiguration {
        ItemView(item) // A SwiftUI View
    }
}

let collectionView: UICollectionView = // 
let dataSource = UICollectionViewDiffableDataSource<Int, Item>(collectionView: collectionView) { collectionView, indexPath, item in
    collectionView.dequeueConfiguredReusableCell(using: makeItemCell, for: indexPath, item: item)
}
0
D-Mx On

Old question but for me the problem was that I was setting all these before viewDidLoad so the collectionView wasn't ready. Check on what part of the lifecycle you're setting things, should be on the viewDidLoad or after.