But whenever I apply a snapshot, even if the new snapshot is exactly the current one from the data source, almost every on-screen cells got reloaded. Here's a simple test view controller:
Code Block swift import UIKit class CollectionViewController: UIViewController { enum Section: Hashable { case main } struct Item: Hashable { let id: String } private lazy var dataSource: UICollectionViewDiffableDataSource<Section, Item> = { return UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { collectionView, indexPath, item in print("data source reloading cell", item, indexPath) let cell = collectionView.dequeueReusableCell( withReuseIdentifier: "cell", for: indexPath ) as! Cell cell.item = item return cell } }() private lazy var listLayout: UICollectionViewCompositionalLayout = { let conf = UICollectionLayoutListConfiguration(appearance: .plain) return UICollectionViewCompositionalLayout.list(using: conf) }() private lazy var regularLayout: UICollectionViewCompositionalLayout = { let item = NSCollectionLayoutItem( layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50)) ) let group = NSCollectionLayoutGroup.horizontal( layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50)), subitem: item, count: 1 ) let section = NSCollectionLayoutSection(group: group) return UICollectionViewCompositionalLayout(section: section) }() private lazy var collectionView: UICollectionView = { let view = UICollectionView(frame: .zero, collectionViewLayout: regularLayout) view.register(Cell.self, forCellWithReuseIdentifier: "cell") view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = .systemBackground return view }() override func viewDidLoad() { super.viewDidLoad() 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), ]) var snapshot = NSDiffableDataSourceSnapshot<Section, Item>() snapshot.appendSections([.main]) snapshot.appendItems((0 ..< 100).map { .init(id: "\($0)") }) dataSource.apply(snapshot, animatingDifferences: false) Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { _ in print("\n\nDelayed Reloading") var snapshot = self.dataSource.snapshot() self.dataSource.apply(snapshot, animatingDifferences: true) } } class Cell: UICollectionViewCell { var item: Item? { didSet { label.text = item?.id } } private(set) lazy var label: UILabel = { let view = UILabel() view.font = .systemFont(ofSize: 48, weight: .semibold) view.translatesAutoresizingMaskIntoConstraints = false return view }() override init(frame: CGRect) { super.init(frame: frame) print("cell inited") contentView.addSubview(label) NSLayoutConstraint.activate([ label.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12), label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -12), ]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } }
Output
Xcode 12.5
iPhone 11 device (iOS 14.5.1)
Code Block Delayed Reloading data source reloading cell Item(id: "2") [0, 2] data source reloading cell Item(id: "4") [0, 4] data source reloading cell Item(id: "6") [0, 6] data source reloading cell Item(id: "8") [0, 8] data source reloading cell Item(id: "10") [0, 10] data source reloading cell Item(id: "12") [0, 12] data source reloading cell Item(id: "14") [0, 14] data source reloading cell Item(id: "1") [0, 1] data source reloading cell Item(id: "3") [0, 3] data source reloading cell Item(id: "5") [0, 5] data source reloading cell Item(id: "7") [0, 7] data source reloading cell Item(id: "9") [0, 9] data source reloading cell Item(id: "11") [0, 11] data source reloading cell Item(id: "13") [0, 13] data source reloading cell Item(id: "15") [0, 15] data source reloading cell Item(id: "0") [0, 0] data source reloading cell Item(id: "11") [0, 11]
Is this an expected behavior?
I've also run the same test on UITableView, which is much more reasonable. Only some off-screen cells are reloaded.