iOS 15 crash at -collectionView:viewForSupplementaryElementOfKind:atIndexPath:

Our code worked for iOS 14.x with Xcode 12.5.x. Updating to Xcode 13.x, we are receiving the following crash anytime we attempt to call collectionView.reloadData() or collectionView.setContentOffset(...).

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath: does not match the element kind it is being used for. When asked for a view of element kind 'HomeSectionBackgroundView' the data source dequeued a view registered for the element kind '(null)'.'

If we replace .reloadData() with .reloadItems(_: ) or .reconfigureItems(_: ), it fixes one of two errors, but how would we correct the .setContentOffset(...) crash?

Answered by IHateXcodeToo in 693227022

Replacing .setContentOffset(...) with .scrollToTop(at: IndexPath(row: 0, section: 0), at: .top, animated: true) resolved error two.

If anyone can, please share more clarity as to why when I return from collectionView:viewForSupplementaryElementOfKind:atIndexPath: that my return ends up nil despite returning a valid view?

Accepted Answer

Replacing .setContentOffset(...) with .scrollToTop(at: IndexPath(row: 0, section: 0), at: .top, animated: true) resolved error two.

If anyone can, please share more clarity as to why when I return from collectionView:viewForSupplementaryElementOfKind:atIndexPath: that my return ends up nil despite returning a valid view?

If anyone can, please share more clarity as to why when I return from collectionView:viewForSupplementaryElementOfKind:atIndexPath: that my return ends up nil despite returning a valid view?

You have closed this thread. So please open a new one and post the complete code of this func.

collectionView:viewForSupplementaryElementOfKind:atIndexPath: 

You have a problem in your dequeue statement.

When asked for a view of element kind 'HomeSectionBackgroundView' the data source dequeued a view registered for the element kind '(null)'.'

It looks like the collection view asks you to return a supplementary view of element kind HomeSectionBackgroundView but then you return a view that you potentially created yourself? Most likely you are not calling -collectionView:viewForSupplementaryElementOfKind:atIndexPath: from inside collectionView:viewForSupplementaryElementOfKind:atIndexPath: or you are calling it with a nil element kind.

Update

Turns out that my workaround did not work. I AM receiving an object, the crash is verified happening at the UIKit level and not in my code. The code runs in iOS 14 and below, and when supplementary cells for type .background(...) are removed, the code works fine. This only appears to be for cells of type .background(...) (this code: https://developer.apple.com/documentation/uikit/nscollectionlayoutdecorationitem/3199051-background)

It is not viewForSupplementaryElementOfKind:atIndexPath: returning nil, it is an Objective-C layer returning nil per Xcode as this code works in iOS 14.x using Xcode 13.x

We have encountered a similar crash on iOS 15.2 (device & simulator), but not on iOS 14.4 (simulator) and have filed Feedback Assistant: FB9812333. Our public tracking issue is https://github.com/roblabs/Maps-for-Messages/issues/1

Issue

Uncaught exception NSInternalInconsistencyException while reviewing Apple Sample Code for iMessage apps.

  • Fails in Xcode 13.2 with an iOS 15.2 device & Simulator.
  • Same sample code works on iOS 14.4 simulator.
  • Same sample code works on Xcode 12.5 with an iOS 14.5 simulator.

Steps to reproduce

This is reproducible with open source code. Since we are reviewing the open source code, we are not sure how to proceed.

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath: does not match the element kind it is being used for. When asked for a view of element kind 'section-header-element-kind' the data source dequeued a view registered for the element kind 'Text'.' terminating with uncaught exception of type NSException

The element kind reference, section-header-element-kind, is a string defined in the view controller class.

iOS 14.4 simulator works

While completing the same steps in an iOS 14.4 simulator, the Apple Sample code works.

  • Test with Xcode Version 13.2 (13C90)
  • Build for iOS 14.4 Simulator

So, the sample app is misusing the API and triggering an assert UIKit added in iOS 15 to catch this.

The sample is incorrectly currently using the same boundary supplementary (therefore the same elementKind) to create multiple supplementary registrations with different classes and elementKinds. Each NSCollectionLayoutBoundarySupplementaryItem must have a unique element kind. Similarly, each UICollectionView.SupplementaryRegistration must have an elementKind matching the appropriate NSCollectionLayoutBoundarySupplementaryItem.

Concretely, this is what it would look like:

let sectionProvider = { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in

    let headerFooterSize = NSCollectionLayoutSize(...)

    switch sectionIndex {
	case 0:
		let section = NSCollectionLayoutSection(...)
	    let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerFooterSize, elementKind: "text", alignment: .topLeading)
		section.boundarySupplementaryItems = [header]
		return section

	case 1:
		let section = NSCollectionLayoutSection(...)
	    let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerFooterSize, elementKind: "picture", alignment: .topLeading)
		section.boundarySupplementaryItems = [header]
		return section

	case 2:
		let section = NSCollectionLayoutSection(...)
	    let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerFooterSize, elementKind: "fancyHeader", alignment: .topLeading)
		section.boundarySupplementaryItems = [header]
		return section

    default:
		return nil

    }
}

Then, when configuring your data source, you'd do this:

let datasource = UICollectionViewDiffableDataSource<Foo, Bar>(...)

let textHeaderRegistration = UICollectionView.SupplementaryRegistration<TextHeaderSupplementaryView>(elementKind: "text") { (supplementaryView, string, indexPath) in
    
    ...
}

let pictureHeaderRegistration = UICollectionView.SupplementaryRegistration<PictureHeaderSupplementaryView>(elementKind: "picture") { (supplementaryView, string, indexPath) in
    
    ...
}

let fancyHeaderRegistration = UICollectionView.SupplementaryRegistration<PictureSupplementaryView>(elementKind: "fancyHeader") { (supplementaryView, string, indexPath) in
    ...
}

datasource.supplementaryViewProvider = { [weak self] (view, kind, indexPath) in
	guard let self = self else { return nil }

	switch indexPath.section {
	case 0:
		return self.collectionView.dequeueConfiguredReusableSupplementary(using: textHeaderRegistration, for: index)

	case 1:
		return self.collectionView.dequeueConfiguredReusableSupplementary(using: pictureHeaderRegistration, for: index)

	case 2:
		return self.collectionView.dequeueConfiguredReusableSupplementary(using: fancyHeaderRegistration, for: index)

    default:
		return nil

    }
}

Note how the element kinds for the boundary supplementary items, the registrations, and the dequeued supplementaries all match. We will also update the sample to fix the crash and correctly use UIKit's API.

iOS 15 crash at -collectionView:viewForSupplementaryElementOfKind:atIndexPath:
 
 
Q