Reconfigure UICollectionView section

Problem

When I reconfigure a collection view snapshot and apply it to my complex production collection view with list layout, the UI updates slowly, unless I don't animate the differences, even though I'm only reconfiguring the specific item identifiers of the cells that should be updated.

I thought that maybe I could speed up the animations of the UI updates by applying the snapshot to a specific section (dataSource?.apply(sectionSnapshot, to: .main)) instead of to the whole collection view (dataSource?.apply(wholeSnapshot)).

The problem is that I can't reconfigure the item identifiers of a single section snapshot to then apply the updated snapshot.

Question

Given the following sample app, can anybody edit reconfigureMainSection() so that, when invoked, the .main section cell registrations are called, consequently invoking print("Reconfiguring")?

Sample app

This collection view with list layout and diffable data source has 1 section and 2 rows.

You can tap the right bar button item to call reconfigureMainSection().

class ViewController: UICollectionViewController {
    var snapshot: NSDiffableDataSourceSnapshot<Section, String> {
        var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
        snapshot.appendSections([.main])
        snapshot.appendItems(["one", "two"], toSection: .main)
        return snapshot
    }
    var dataSource: UICollectionViewDiffableDataSource<Section, String>?
    
    enum Section {
        case main
    }
    
    init() {
        super.init(collectionViewLayout: .init())
                
        collectionView.collectionViewLayout = createLayout()
        configureDataSource()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        navigationItem.rightBarButtonItem = .init(
            title: "Reconfigure",
            style: .plain,
            target: self,
            action: #selector(reconfigureMainSection)
        )
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func configureDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in
            print("Reconfiguring")
        }
        
        dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier)
        }
        
        dataSource?.apply(self.snapshot, animatingDifferences: false)
    }
    
    func createLayout() -> UICollectionViewLayout {
        return UICollectionViewCompositionalLayout { section, layoutEnvironment in
            let config = UICollectionLayoutListConfiguration(appearance: .plain)
            return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
        }
    }
    
    @objc func reconfigureMainSection() {        
        var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<String>()
        sectionSnapshot.append(snapshot.itemIdentifiers(inSection: .main))

        // reconfigure the section snapshot
        
        dataSource?.apply(sectionSnapshot, to: .main)
    }
}

Environment

MacBook Air M1 8GB

macOS Sonoma 14.5

Xcode 15.4

iPhone 15 Pro simulator on iOS 17.5

Answered by DTS Engineer in 801740022

@Filippo02 Currently, there is no a 1-1 mapping for that method for sections. To get equivalent behavior in sections, you may need to manually get the indexPath and reconfigureItemsAtIndexPaths

@Filippo02 Have a look MountainsViewController.swift soruce file in Implementing Modern Collection Views sample project. In that example, you'll notice that when performQuery(with filter: String?) is called the UI is updated to reflect the changes for a particular section identifier.

@DTS Engineer Thank you for your reply, but, given that the body of the mentioned function is as follows, your answer is not pertinent to my question, since the item identifiers of the section are not reconfigured:

let mountains = mountainsController.filteredMountains(with: filter).sorted { $0.name < $1.name }

var snapshot = NSDiffableDataSourceSnapshot<Section, MountainsController.Mountain>()
snapshot.appendSections([.main])
snapshot.appendItems(mountains)
dataSource.apply(snapshot, animatingDifferences: true)

By using the word "reconfigure", I hoped I had made clear that I am looking for a method like reconfigureItems(withIdentifiers:) of NSDiffableDataSourceSnapshot but for NSDiffableDataSourceSectionSnapshot.

Accepted Answer

@Filippo02 Currently, there is no a 1-1 mapping for that method for sections. To get equivalent behavior in sections, you may need to manually get the indexPath and reconfigureItemsAtIndexPaths

Reconfigure UICollectionView section
 
 
Q