Filippo
Filippo

Reputation: 150

"Attempted to dequeue a cell for a different registration or reuse identifier than the existing cell when reconfiguring an item, which is not allowed"

Searching for my very title (including the quotes) generated no results on Google.

If you run this UIKit app and tap the right bar button item:

class ViewController: UIViewController {
    var boolean = false {
        didSet {
            var snapshot = self.snapshot
            snapshot.reconfigureItems(snapshot.itemIdentifiers) // if you comment this out the app doesn't crash
            dataSource.apply(snapshot)
        }
    }
    var snapshot: NSDiffableDataSourceSnapshot<String, String> {
        var snapshot = NSDiffableDataSourceSnapshot<String, String>()
        snapshot.appendSections(["main"])
        snapshot.appendItems(boolean ? ["one"] : ["one", "two"])
        return snapshot
    }
    
    var collectionView: UICollectionView!
    
    var dataSource: UICollectionViewDiffableDataSource<String, String>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureHierarchy()
        configureDataSource()
    }
    
    func configureHierarchy() {
        collectionView = .init(frame: .zero, collectionViewLayout: createLayout())
        view.addSubview(collectionView)
        collectionView.frame = view.bounds
        
        navigationItem.rightBarButtonItem = .init(
            title: "Toggle boolean",
            style: .plain,
            target: self,
            action: #selector(toggleBoolean)
        )
    }
    
    @objc func toggleBoolean() {
        boolean.toggle()
    }
    
    func createLayout() -> UICollectionViewLayout {
        UICollectionViewCompositionalLayout { section, layoutEnvironment in
            let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
            return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
        }
    }
    
    func configureDataSource() {
        let cellRegistration1 = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in
            
        }
        let cellRegistration2 = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in
            
        }
        
        dataSource = .init(collectionView: collectionView) { [unowned self] collectionView, indexPath, itemIdentifier in
            if indexPath.row == 0 && boolean {
                collectionView.dequeueConfiguredReusableCell(using: cellRegistration1, for: indexPath, item: itemIdentifier)
            } else {
                collectionView.dequeueConfiguredReusableCell(using: cellRegistration2, for: indexPath, item: itemIdentifier)
            }
        }
        
        dataSource.apply(self.snapshot, animatingDifferences: false)
    }
}

it crashes with that error message.

The app uses a collection view with list layout and a diffable data source.

It has one section, which should show one row if boolean is true, two if it's false.

When boolean changes, the collection view should also reconfigure its items (in my real app, that's needed to update the shown information).

If you comment out snapshot.reconfigureItems(snapshot.itemIdentifiers), the app no longer crashes.

What's the correct way of reconfiguring the items of a diffable data source then?

iOS 17.5, iPhone 15 Pro simulator, Xcode 15.4, macOS 17.5, MacBook Air M1 8GB.

Upvotes: 0

Views: 195

Answers (0)

Related Questions