UICollectionViewDiffableDataSource cellProvider 的调用频率高于预期
UICollectionViewDiffableDataSource cellProvider called more often than expected
我正在使用 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 函数的前半部分行为异常每次调用 returns 相同的单元格,即使 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
}
这是一个例子:
- 我创建了一个包含 4 个供应商条目的快照(为简单起见,我没有在本示例的其他部分中添加任何内容)
- cellProvider 被调用了 4 次(针对每个 indexPath 和 entry),每次出队的 cell 都是同一个。
- cellProvider 又被调用了 4 次(同样,对于每个 indexPath 和条目),这次单元格每次都不同。
- 每次调用 cellProvider 时,我都会调用 loadImage,它会尝试在我的图像缓存中为 URL 查找图像,如果找不到则异步加载它。
- 由于所有调用几乎同时发生,每个图像都被加载两次,第一个单元格显示一个接一个图像,直到它发起的 4 个 URL 会话中的最后一个 returns。
我无法想象 dataSource 经常调用它的 cellProvider 闭包是预期的行为,我根本无法弄清楚为什么会发生这种情况,也无法在文档中找到任何相关内容。
我希望有人能向我解释为什么会发生这种情况,如果这是预期的行为,如何使用 DiffableDataSource 正确设置具有异步图像加载的单元格。
编辑:
正如@Norb Braun 所建议的,对我有用的解决方案是对我的单元格使用绝对大小而不是估计大小!
将估计大小设置为 none
为我解决了这个问题。当您需要使用自动调整大小的单元格时,此解决方案可能不适合您,但如果您的单元格无论内容如何都保持相同大小,您可以尝试一下。
我正在使用 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 函数的前半部分行为异常每次调用 returns 相同的单元格,即使 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
}
这是一个例子:
- 我创建了一个包含 4 个供应商条目的快照(为简单起见,我没有在本示例的其他部分中添加任何内容)
- cellProvider 被调用了 4 次(针对每个 indexPath 和 entry),每次出队的 cell 都是同一个。
- cellProvider 又被调用了 4 次(同样,对于每个 indexPath 和条目),这次单元格每次都不同。
- 每次调用 cellProvider 时,我都会调用 loadImage,它会尝试在我的图像缓存中为 URL 查找图像,如果找不到则异步加载它。
- 由于所有调用几乎同时发生,每个图像都被加载两次,第一个单元格显示一个接一个图像,直到它发起的 4 个 URL 会话中的最后一个 returns。
我无法想象 dataSource 经常调用它的 cellProvider 闭包是预期的行为,我根本无法弄清楚为什么会发生这种情况,也无法在文档中找到任何相关内容。
我希望有人能向我解释为什么会发生这种情况,如果这是预期的行为,如何使用 DiffableDataSource 正确设置具有异步图像加载的单元格。
编辑: 正如@Norb Braun 所建议的,对我有用的解决方案是对我的单元格使用绝对大小而不是估计大小!
将估计大小设置为 none
为我解决了这个问题。当您需要使用自动调整大小的单元格时,此解决方案可能不适合您,但如果您的单元格无论内容如何都保持相同大小,您可以尝试一下。