问题
I have a problem with NSDiffableDataSource
. I have created this basic example containing a UICollectionView
with a single item showing a random number:
import UIKit
class ViewController: UIViewController {
enum Section {
case main
}
enum Item {
case myItem
}
var collectionView: UICollectionView!
var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
lazy var myCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Void> { (cell, indexPath, _) in
print("Cell registration called")
var content = cell.defaultContentConfiguration()
content.text = "\(Int.random(in: 0...10000))"
cell.contentConfiguration = content
}
override func viewDidLoad() {
super.viewDidLoad()
var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
let layout = UICollectionViewCompositionalLayout.list(using: config)
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .systemGroupedBackground
view.addSubview(collectionView)
NSLayoutConstraint.activate([
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
collectionView.topAnchor.constraint(equalTo: view.topAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: { [unowned self] (collectionView, indexPath, item) -> UICollectionViewCell? in
switch item {
case .myItem:
return collectionView.dequeueConfiguredReusableCell(using: myCellRegistration, for: indexPath, item: ())
}
})
DispatchQueue.global(qos: .background).async {
while true {
sleep(2)
DispatchQueue.main.async {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.main])
snapshot.appendItems([.myItem])
self.dataSource.apply(snapshot, animatingDifferences: true)
}
}
}
}
}
Every 2 seconds, I re-apply the same snapshot to the data source. As the snapshot doesn't change, I expect the cell to not be updated either. And that is the case ... kind of. Visually, the cell does not change (the displayed number stays the same). However, the data source actually calls the cell registration closure every time the snapshot updates, so the cell's content configuration actually does change. It's just not being drawn.
Does anybody know what's going on here?
To give a little bit of background: The reason I'm asking about this is that I want to subscribe to a Combine
publisher
when creating the content configuration of the cell. The publisher then publishes the data for the cell and the cell can update its views, allowing custom animations. (I could simply put the data into an item identifier
, but then any data change would simply result in the cell cross-fading into the new one. That's not nice).
It would look something like this:
// Event.Cell is some custom cell with a custom content configuration
lazy var myCellRegistration = UICollectionView.CellRegistration<Event.Cell, Void> { [unowned self] (cell, indexPath, _) in
var content = Event.ContentConfiguration()
self.myEventPublisher.sink { event in
content.event = event
cell.contentConfiguration = content // Re-set the contentConfiguration
}.store(in: &content.disposeBag) // store the subscriber in a dispose bag inside the content configuration
}
Since working with publishers and subscribers can be tricky (memory leaks and stuff), I need to know how to do this without causing any problems and the snapshot is behaving strangely. At least to me it seems that way
来源:https://stackoverflow.com/questions/64818655/nsdiffablesnapshot-causes-collectionviews-cell-registration-to-be-re-called-eve