I am testing iOS15 and some new functionalities of UIKit. I've encountered some issues, not sure how to solve them. I did not change that code. This is just a piece of code that worked perfectly with the iOS 14, now after updating my target, it throws an error.
Xcode crashes the moment when my custom header for the UICollectionView of type UICollectionElementKindSectionHeader is being returned for the dataSource. Here is my code:
private func configureDataSource() {
dataSource = UICollectionViewDiffableDataSource<Section, Follower>(collectionView: collectionView, cellProvider: { (collectionView, indexPath, followers) -> UICollectionViewCell? in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FollowerCell.reuseId, for: indexPath) as! FollowerCell
cell.set(on: followers)
return cell
})
dataSource.supplementaryViewProvider = { (collectionView, kind, indexPath) in
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: FollowersCollectionHeaderView.reuseId,
for: indexPath) as! FollowersCollectionHeaderView
header.set(with: self.user)
return header
}
}
The log says:
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 'FollowersCollectionHeaderView' the data source dequeued a view registered for the element kind 'UICollectionElementKindSectionHeader'.
I did cast UICollectionElementKindSectionHeader to FollowersCollectionHeaderView, therefore I am not sure what is the issue here.
I've watched WWDC21 what's new in UIKit but haven't seen any mentioning of any change for that particular code.
Any suggestions, what to fix in that code?
In order to understand the problem, we need to review how UICollectionView supplementary and decoration views work.
Supplementary (and Decoration) Views
Immediately before the crash, UICollectionView asked your data source for a supplementary view, either by calling the method collectionView(_:viewForSupplementaryElementOfKind:at:)
(documentation) if you have a custom data source implementation, or by calling your supplementaryViewProvider
(documentation) if you are using a diffable data source.
When the collection view asks you for a supplementary view, it passes a String that represents the element kind of the supplementary that the collection view needs.
The element kind is used to differentiate multiple types of supplementary and/or decoration views — for example, you might have two supplementary views for each section of a list: a section header and a section footer.
Defining Element Kinds
Your collection view layout is what defines the element kinds you are using for supplementary and decoration views.
Collection view lists built with UICollectionLayoutListConfiguration and flow layouts built with UICollectionViewFlowLayout utilize special string constants for their supplementary view element kinds:
- Section headers use an element kind of elementKindSectionHeader (for flow layout, and lists using
headerMode = .supplementary
(documentation)) - Section footers use an element kind of elementKindSectionFooter (for flow layout, and lists using
footerMode = .supplementary
(documentation))
If you're building a custom UICollectionViewCompositionalLayout, you choose the element kind strings for your supplementary and decoration views when defining your layout using NSCollectionLayoutSupplementaryItem, NSCollectionLayoutBoundarySupplementaryItem, and NSCollectionLayoutDecorationItem.
Using Element Kinds
When you register a class or nib for a supplementary, you specify the element kind that you are creating the registration for.
- Each SupplementaryRegistration is created with the element kind.
- Or, if you're still using the methods to register a class or nib manually, you specify both the element kind and reuse identifier that you are registering for.
You need at least one supplementary registration for each element kind that your layout uses.
Then, when the collection view needs a supplementary view, it asks its data source to provide the view for the specific element kind it needs at that particular moment. If you have multiple types of supplementary views, each element kind is requested separately, and depending on your layout, you might even have multiple supplementaries (with different element kinds) for the same index path.
Therefore, it is your responsibility to look at the element kind of the supplementary view that UICollectionView is asking for, and make sure that you dequeue & return a supplementary view for that element kind. (You can have multiple SupplementaryRegistration
or registered reuse identifiers for each element kind, if desired, and it's up to you to pick which one to use. But you must always dequeue a supplementary view for the element kind that the collection view is requesting.)
Fixing the Crash
With that understanding, let's revisit the exception message for this crash, in particular the second sentence:
When asked for a view of element kind 'FollowersCollectionHeaderView' the data source dequeued a view registered for the element kind 'UICollectionElementKindSectionHeader'.
What this is telling you is that UICollectionView asked your data source for a supplementary view for element kind 'FollowersCollectionHeaderView'
, but you dequeued & returned a supplementary view for a different element kind 'UICollectionElementKindSectionHeader'
(which is the raw string value of the special elementKindSectionHeader constant).
To fix this, you'll need to look at the implementation of your collectionView(_:viewForSupplementaryElementOfKind:at:)
method or supplementaryViewProvider
on your data source. Make sure that you always use the element kind passed in when you go to dequeue a supplementary view in your implementation. You are free to choose any SupplementaryRegistration
or reuse identifier that you previously registered for that element kind, but you cannot dequeue & return a supplementary view for a different element kind than the one the collection view is requesting.