dataSource.snapshot().itemIdentifiers(inSection:) works extremely inefficient

72 views Asked by At

Consider an app that uses UICollectionViewDiffableDataSource for the data source of UICollectionView.

private func makeDataSource() -> DataSource {
    return DataSource(collectionView: collectionView) { collectionView, indexPath, task in
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TaskCell", for: indexPath) as? TaskCell
        cell?.title = task.title
        return cell
    }
}

Collection has only one section:

enum Section {
    case main
}

and loads 10 000 items represented by Task:

import Foundation

struct Task {
    let id: String
    let title: String
}

extension Task: Hashable {
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

ViewController that holds the collection, implements sizeForItemAt and calculate size based on e.g. title length:

func collectionView(
    _ collectionView: UICollectionView,
    layout collectionViewLayout: UICollectionViewLayout,
    sizeForItemAt indexPath: IndexPath
) -> CGSize {
    let task = dataSource.snapshot().itemIdentifiers(inSection: .main)[indexPath.item]
    let height = calculateHeight(for: task)
    return CGSize(width: collectionView.frame.width, height: heigh)
}

Now it works fine, except that .itemIdentifiers(inSection: .main) works extremely slow as for its complexity. Every call of this function takes few milliseconds which multiplied by 10 000 results in blocking UI for few seconds.

Why .itemIdentifiers(inSection:) is so slow? How else can I access item identifier when I want to calculate cell size making sure that it is synchronized with snapshot?

0

There are 0 answers