CollectionView с использованием NSDiffableDataSource с UICollectionViewFlowLayout

Когда я использую UICollectionView с установленным UICollectionViewFlowLayout. А затем попробуйте применить снимки источника данных через

// load initial data
        reloadDataSource()

        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
            self.reloadDataSource(animating: true)
        }

Я получаю сбой при применении второго снимка после 3-секундной задержки. Вылет происходит только при анимации: true

Если я установил для анимации значение false, сбоя не будет, но если оставить пустой вид коллекции.

Вот этот метод применения источника данных

extension CollectionViewController {

    func reloadDataSource(animating: Bool = false) {

        print("reloading data source with snapshot -> \(snapshot.numberOfItems)")

        self.dataSource.apply(self.snapshot, animatingDifferences: animating) {
            print("applying snapshot completed!")
        }
    }
}

Источник данных просто

let dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: cellProvider)

Полный проект, в который вы можете играть (со временем может измениться): https://github.com/michzio/SwifUICollectionView

Обновить

Я попытался упростить пример и сделать что-то вроде этого, но он работает неправильно. Кажется, что перемещение.apply() в фоновую очередь, другая очередь вызывает пустые данные в коллекции

func reloadDataSource(animating: Bool = false) {

        print("reloading data source with snapshot -> \(snapshot.numberOfItems)")
        diffQueue.async {
            var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
            snapshot.appendSections([.categories])
            snapshot.appendItems(Item.categoryItems)

            self.dataSource.apply(snapshot, animatingDifferences: animating) {
                print("applying snapshot completed!")
            }
        }
    }

1 ответ

Хорошо, похоже, я нашел причину всех своих ошибок с обновлением источника данных, применив новые снимки

Этот ленивый источник данных var вызывает ошибки:

private(set) lazy var dataSource: UICollectionViewDiffableDataSource<Section, Item> = {
        let dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: cellProvider)
        //dataSource.supplementaryViewProvider = supplementaryViewProvider
        return dataSource
    }()

Я изменил это на

private(set) var dataSource: UICollectionViewDiffableDataSource<Section, Item>!

и после configureCollectionView в viewDidLoad() теперь я вызываю configureDataSource(), который выполняет то, что было в инициализаторе lazy var.