comments 2

# 40 How to swiftly dequeue a cell?

The UITableView and UICollectionView classes serve table-like and matrix-like layout for content to be displayed on screen. Both components display their data in corresponding UITableViewCell and UICollectionViewCell subclasses. Both components contain mechanisms for reusing a cell, that was initialised earlier and is not visible on the screen, e.g. when user scrolled the content. You can find a nice description and visualisations on that subject here.

Reusing a UITableViewCell – an old way

In order to reuse a cell in a tableView, the cell has to be registered for reuse with an identifier. Usually it is done at the time you configure your views, e.g. in viewDidLoad.

To reuse a cell it has to be dequeued from a tableView. Dequeueing is done by dequeueReusableCell(withIdentifier:for:) method. It dequeues a cell or initialises a new one if none is queued for reuse.

Have you noticed the "MyCell" duplicated in viewDidLoad and tableView(cellForRowAt:)? It felt ugly to me so I have decided to refactor that code, when I repeated it in a few view controllers.

I refactored the code so that a cell I registered for reuse from a stored cellClass and a computed property cellIdentifier.

Actually, this approach is kinda nice if we have a few cells to be registered for reuse. We can do some functional magic 🔮, like this:

The cellIdentifier property is of course used in tableView(cellForRowAt:). What I still don’t like in this code is that I still have to cast the reused cell to an appropriate type, even though I stored a cellClass 😭.

Finally, my colleague Alek has invented a great solution to my problem!

Extending UITableViewCell

First of all, it is a tedious work to write cellIdentifier property in every view controller. Why not to extend the UITableViewCell?

Then we can further extend a UITableView with a new version of register method to make use of identifier property on a UITableViewCell.

But the most beautiful magic 🔮 happens when we extend UITableView with new version of dequeueReusableCell(...) method! It uses generics, takes as an argument a class of a cell, an indexPath and a configure closure to which a cell of desired type (i.e. of CellClass.Type) is passed. No more guard and casting in tableView(cellForRowAt:)! Yuppii 😊!

So now we can easily dequeue a cell of an appropriate type! How neat is that 😀 !?

Wrap up

The presented approach simplifies cell registration for reuse and allows to avoid guard-cell-casting. The same approach can be used for UICollectionView.

What you cannot do with the presented solution is taking cellClass from an array, because a compiler doesn’t know type at compile time.


What you can do with that is of course using a switch statement, e.g. over section, to infer a cell type.

You can play with the solution by downloading our playgrounds or by grabbing gists from links section.

Links

2 Comments

  1. Henry

    Nice article! I prefer this though:


    public extension UITableView {
    public func registerCell(_ cellType: UITableViewCell.Type) {
    self.register(cellType, forCellReuseIdentifier: String(describing: cellType))
    }

    public func dequeueCell(_ cellType: T.Type, for indexPath: IndexPath) -> T where T: UITableViewCell {
    return self.dequeueReusableCell(withIdentifier: String(describing: cellType), for: indexPath) as! T
    }
    }

Leave a Reply


*