Image from UITableView documentation

Advanced configuration of UITableViewCell-s

Mike Haidan
3 min readSep 11, 2021

--

How often do you write/see code like this?

I don’t like such setup because it breaks Open-close principle and, if we have a really complex structure we will get an endless list of if-else conditions. In the end it’s really hard to control.

I’d like to propose an approach, which I’m using almost for every UITableView component.

I’ll describe it with a simple example.

First, let’s get started with a usual UITableView setup. Assume, that we have a Profile screen with following components:

  • First name and last name
  • Profile Image
  • Bio

The prototype result may looks like this:

And Profile model:

As usual, we will create 3 cells (the source code is attached to each name):

Each cell accepts Profile model as a parameter, so cells have such function:

func setup(with profile: Profile) { 
...
}

And our final TableView setup looks like this:

Listing of the ViewController can be found here.

What I can say about this implementation.

Image from Chernobyl TV series

This approach may work, but what if we need to add a new item, we will get a new case block. Also we can forget to update a number of the items and so on…

Let’s try in another way!

First let’s add a Protocol.

protocol ReusableItem {
var reuseIdentifier: String { get }
}

It simply has one computed property, which will return a reuseIdentifier of custom UITableViewCell.

Now, we will create an Abstract UITableViewCell.

Pretty simple. We have just one method, which accepts ReusableItem and which has to be overridden by it’s child.

Now, we need to create models that represent each cell.

  1. Implementation of ReusableItem protocol. Each model returns a reusable identifier of it’s UITableViewCell.
  2. Params, which are necessary for specific UITableViewCell.

Now, we will add one helper property to our Profile model:

This computed property transforms the Profile model to an array of ReusableItems.

Next, each cell has to inherit from BaseReusableTableViewCell and implement “func setup(with model: ReusableItem)” method.

  1. We can cast to “Cell” model using force unwrap without any doubts, because each model represents it’s own cell.
  2. Setting up cells properties.

And final updates in the ViewController.

  1. Instead of using profile directly, dataSource has been added, which we will use for UITableViewDataSource.
  2. Settings up dataSource, using computed property from Profile, which has been added recently.
  3. As you can see, the switch has been replaced by a few lines of code. No matter how many components we have in Profile, the implementation won’t be affected.
  4. Instead of “hard coded” value, dataSource.count is used. Now we don’t care about the number of items for UITableView.

And that’s it! Implementation is done. What benefits it has:

  • We can easily rearrange, remove, add new items. UIViewController stays untouchable.
  • No matter how complex the UI is, the setup is always the same.
  • We can write unit tests for data source setup! Because setup has been removed from the ViewController and moved to the model instead (In real world it can be moved to Presenter or ViewModel).
  • We can easily reuse cells, because they are specific to their own data.
  • This appraoch really easy to implement!

Hope this article will help build much flexible UITableView.

Thank you for reading ❤️.

Full implementation you can find here.

--

--