Configure collection view cells with UICollectionView.CellRegistration
Published on: June 24, 2020In iOS 14 you can use the new UICollectionView.CellRegistration
class to register and configure your UICollectionViewCell
instances. So no more let cellIdentifier = "MyCell"
, no more collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath)
and best of all, you no longer need to cast the cell returned by dequeueReusableCell(withReuseIdentifier:for:)
to your custom cell class.
Adopting UICollectionView.CellRegistration
in your project is surprisingly straightforward. For demo purposes I created the following UICollectionViewCell
subclass:
class MyCollectionViewCell: UICollectionViewCell {
let label = UILabel()
required init?(coder: NSCoder) {
fatalError("nope!")
}
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor, constant: 8).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.leadingAnchor, constant: 8).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.bottomAnchor, constant: -8).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.trailingAnchor, constant: -8).isActive = true
}
}
To register this cell on a collection view using UICollectionView.CellRegistration
all you need is an instance of UICollectionView.CellRegistration
that's specialized for your cell class and data model. My case I'm going to use a String
as my data model since the cell only has a single label. You can use any object you want for your cells. Usually it will be the model that you retrieve in the cellForItemAt
delegate method.
// defined as an instance property on my view controller
let simpleConfig = UICollectionView.CellRegistration<MyCollectionViewCell, String> { (cell, indexPath, model) in
cell.label.text = model
}
Notice that UICollectionView.CellRegistration
is generic over two types. The UICollectionViewCell
that I want to use, and the model type which is a String
in my case. The initializer for UICollectionView.CellRegistration
takes a closure that's used to set up the cell. This closure receives a cell, an index path and the model that's used to configure the cell.
In my implementation I simply assign my String
model to cell.label.text
.
You don't have to register your UICollectionView.CellRegistration
on your UICollectionView
. Instead, you can use it when you ask your collection view to dequeue a reusable cell in cellForItemAt
as follows:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let model = "Cell \(indexPath.row)"
return collectionView.dequeueConfiguredReusableCell(using: simpleConfig,
for: indexPath,
item: model)
}
When you call dequeueConfiguredReusableCell(using:for:item:)
on a UICollectionView
, it dequeues a cell that has the correct class and the closure that you passed to your UICollectionView.CellRegistration
initializer is called so you can configure your cell.
All you need to do is make sure that you grab the correct model from your data source, pass it to dequeueConfiguredReusableCell(using:for:item:)
and return the freshly obtained cell. That's all there is to it! Pretty nifty right? There's no other special setup involved. No secret tricks. Nothing. Just a much nicer way to obtain and configure collection view cells.