UICollectionViewDiffableDataSource cellProvider вызывается чаще, чем ожидалось

Я использую UICollectionViewDiffableDataSource для заполнения моего UICollectionView. Получив список элементов через REST API, я создаю новый снимок и применяю его следующим образом:

DispatchQueue.main.async {
   var snapshot = NSDiffableDataSourceSnapshot<RegionSection, DiffableModel>()
   snapshot.appendSections(RegionSection.allCases)
   snapshot.appendItems(self.spotlights, toSection: .Spotlights)
   snapshot.appendItems(self.vendors, toSection: .Vendors)
   self.dataSource?.apply(snapshot, animatingDifferences: animated)
}

При настройке ячеек в cellProvider я асинхронно загружаю изображения с URL-адреса. Я заметил, что первая ячейка отчаянно пролистывала все загруженные изображения и в конечном итоге показывала другое изображение, чем предполагалось. (Например, изображение, предназначенное для отображения в последней ячейке).

Я решил исследовать и выяснил, что закрытие cellProvider вызывается в два раза чаще, чем ожидалось. Также функция collectionView.dequeueReusableCell ведет себя странно для первой половины вызовов, поскольку она каждый раз возвращает одну и ту же ячейку, даже если в collectionView нет ячеек, которые можно было бы исключить из очереди.

Закрытие моего cellProvider:

dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { (collectionView, indexPath, entry) -> UICollectionViewCell? in
    if let spotlight = entry as? Spotlight{
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "spotlightCell", for: indexPath) as! SpotlightCell
        
        cell.nameLabel.text = spotlight.title
        cell.subtitleLabel.text = spotlight.subtitle
        cell.categoryLabel.text = spotlight.type.getDescription().uppercased()
        cell.imageView.loadImage(fromUrl: spotlight.titlePictureUrl)
                    
        return cell
    }else if let vendor = entry as? Vendor{
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "vendorCell", for: indexPath) as! VendorCell
        
        cell.nameLabel.text = vendor.title
        cell.assortmentLabel.text = vendor.assortmentDescription
        cell.imageView.loadImage(fromUrl: vendor.titlePictureUrl ?? vendor.pictureUrls?.first ?? "")
        
        if let distance = vendor.distance{
            cell.distanceLabel.text = (distance/1000) < 1 ? (distance.getReadableString(withDecimalSeparator: ",", andDecimalCount: 0) + "m entfernt") : ((distance/1000).getReadableString(withDecimalSeparator: ",", andDecimalCount: 0) + "km entfernt")
        }
                    
        return cell
    }
    return nil
}

Вот пример:

  1. Я создаю снимок, содержащий 4 записи о поставщиках (для простоты я ничего не добавил в другой раздел для этого примера)
  2. CellProvider вызывается 4 раза (для каждого indexPath и каждой записи), и каждый раз удаляемая ячейка остается одной и той же.
  3. CellProvider вызывается еще 4 раза (снова для каждого indexPath и каждой записи), и на этот раз ячейки каждый раз разные.
  4. Каждый раз, когда вызывается cellProvider, я вызываю loadImage, который пытается найти изображение для URL-адреса в моем кеше изображений, и, если он не может найти, загружает его асинхронно.
  5. Поскольку все вызовы происходят почти одновременно, каждое изображение загружается дважды, и первая ячейка отображает одно изображение за другим, пока не вернется последний из 4 инициированных им сеансов URL.

Я не могу себе представить, что это ожидаемое поведение для dataSource, чтобы вызывать его закрытие cellProvider так часто, и я просто не могу понять, почему это происходит, или найти что-нибудь в документации по этому поводу.

Я надеюсь, что кто-нибудь сможет объяснить мне, почему это происходит, и в случае, если это ожидаемое поведение, как правильно настроить ячейки с асинхронной загрузкой изображений с помощью DiffableDataSource.

1 ответ

Установка приблизительного размера на noneисправил эту проблему для меня. Это решение может не работать для вас, когда вам необходимо использовать ячейки с самодиагностикой, но если ваши ячейки сохраняют тот же размер независимо от содержимого, вы можете попробовать.