Cell models based UI in iOS development

David Jiménez Guinaldo
Ninety Nine Product & Tech
8 min readDec 14, 2021
by Pawel Czerwinski

Dealing with the initial stage of any start-up project is always a challenge. Since we are in quite an uncertain environment in which we should be able to face changes that could come up in very short periods it’s crucial to have in mind maintainability and scalability from the beginning.

When the code foundation is being built we should anticipate future issues that could appear and try to answer many questions like:
- How difficult would be for newcomers to get down to business?
- How long would it take to change completely the order of the components of that scene if the Product team requires it?
- Are we able to reuse this component in other scenes easily?
- How tough would be for one of our peers to grasp without any context the code of the feature we wrote months ago?
- …

For solving this on the UI side, we have used a cell models based approach… By now you should be wondering: “What the heck is a cell model!?” Let’s deep dive into it!

UITableView is one of the most commonly used and very well-known components of UIKit. They are essential in the majority of apps because they provide us with 2 great benefits: reusability, and an easy way of scrolling our content (everybody fears the UIScrollView!)

by @SwapnanilDhol

So, what prevents us from using UITableView extensively? Nothing at all! Or well… maybe you are thinking about tons of bad experiences you had in the past coping with complex scenes in which many different types of cells were required… and even worse, different states would be redrawing the whole scene, reordering some of those cells, hiding some others and introducing new ones…

Wouldn't be great if instead of that we could have something similar to this and extract it from the ViewController?:

That’s what we want to achieve in the end: an array of elements that could provide us with a simple way of recognizing in a glance of code how the scene will look like. And those elements are what we’ll be calling from now on cell models. So let’s define 3 principles:

  • UITableView will be used extensively through almost all the app
  • We won’t be using directly UITableViewCell itself but a custom new object called CellModel. So every UITableViewCell will be backed by a CellModel
  • Every CellModel should contain all the info needed to draw the cell, and the mechanisms to interact with inner tappable UI elements as UIButton, UISwitch, UISlider, etc…

Let’s take a quick look at one of the main scenes of the Ninety Nine app, and get a high-level point of view of how the cell models play their role:

Every colored rectangle represents a different instance of cell model, every color represents a different type of cell model. As you can tell, we can even get cell models into another cell model. This is possible always that the parent one houses an inner table view or collection view as it’s happening with the green-rectangular and the orange-rectangular ones.

Let’s code a bit…

The cell model foundations

What we are ultimately looking for is to find a solution that enables us to reduce the logic of the cells that previously dwelled in the ViewController and move it to our ViewModel (we use MVVM, but this applies to any other design pattern, as MVP or VIPER) that will be UIKit agnostic but also the piece accountable of which cells we’ll be needed and how will be them displayed.

So, let’s present the main characters of our show…

What is a CellModel in terms of code? Just a struct that has to conform to this protocol:

As simple as this. Since there is a 1–1 relationship between UITableViewCells and CellModels we just need an identifier of CellIdentifier type to pair them. All the cell model structs will be conforming to this protocol. And each new cell model will have its own and unique CellIdentifier.

Now, comes into play a new protocol, CellModelConfigurable:

This one is thought to be conformed by the own UITableViewCells. It includes the generic CustomCellModel associatedtype that will allow us to define which exact CellModel we’ll be expecting for the cell’s configuration purpose.

Time to present a new and key character, a class called CellBuilder:

At first glance, this might seem like the ugly duckling of our show… and I’m not going to lie to you, it indeed is! The bad news is that as time goes by and the project grows, the CellBuilder will become uglier and uglier since it houses all the configurations for each type of cell.

The good news? That every time you have to use it in your ViewControllers, it will look like a swan to you 😍

This was the RxSwift version. But of course, you can adapt it to your project’s needs and, for example, use it directly in the cellForRow method of UITableViewDelegate:

As simple as this. Forget about adding any other code related to cells in your ViewController.

To finish our cell model foundations, let’s add an UITableView extension that will enable us to register the specific type we are going to use in that table view:

Everything is set to get our hands dirty!

Demo project

These kinds of posts are quite tedious and even nonsense without having a practical example that lets us follow visually all the bunches of code that are shown here. That’s why I encourage you to download it and start playing around:

The demo project uses MVVM + RxSwift with exactly the same cell model’s foundation described previously. That base code should be a good start point for almost every approach and stack that you might be using in yours. From this point, I’ll be presenting what I think are great approaches in a reactive environment.

Getting to know our demo project’s cell models

MainScene dissection

We can tell between 5 different types of cell models:

  • BannerCellModel (green): A simple and dismissable banner.
  • SegmentedMenuCell (red): A menu for choosing between different types of sorting options.
  • ElementsHorizontalContainerCellModel (yellow): An horizontal collection view thought to contain ElementCollectionCellModel.
  • ElementCollectionCellModel (purple): A simple visual representation of the element model thought to be used in UICollectionView.
  • ElementCellModel (orange): A simple visual representation of the element model thought to be used in UITableView.

As you may notice, a new CollectionCellModel (ElementsHorizontalContainerCellModel) type has been introduced. This is because all the previous code highly focused on table views can be easily extrapolated for being used in collection views following the same approaches. Check out CollectionCellModelProtocols.swift, CollectionCellIdentifier.swift, CollectionCellBuilder.swift files at CellModelCore project’s folder.

All the previous code highly focused on table views can be easily extrapolated for being used in collection views

Building scenes

From now on we could follow multiple approaches to provide the cell models to our ViewController’s CellBuilder. The standard one would be just to create an array that contains the CellModels elements in the same order that we expected their UITableViewCells to be displayed in that scene. We are going a step further and taking advantage of the latest Swift features to create our own DSL (through the use of Result Builders) in order to achieve a more readable syntax in our code when it comes to building these CellModel’s DataSources.

Let’s also create a new protocol DataSourceBuildable that’ll be conformed by those classes that contain an UITableView:

And there we are! Now we can build our data sources in this cool way 😎:

Instead of the old-fashioned one 😕:

Context of refresh

If we want to avoid any undesired behavior and visual glitches we have to be aware of the refresh context of each cell model use case. In some cases, we’d need to refresh all the cell models because a completely new structure of them is required, but in others, only one or a few of them should refresh their content.

This demo project contains a deliberate example of this kind of misbehavior:

As you can tell the UISegmentedControl is not working properly. It was supposed to be smooth in its transition between options. This is happening because we are rebuilding the whole cell models data source and that includes the own SegmentedCellModel.

Meanwhile, this is the behavior when it comes to sorting the horizontal list of elements:

It works as expected! And this is due to the handling of the sorting action by the own ElementsHorizontalContainerCellModel.

Last words

I started to play with this kind of approach around 3 years ago, always seeking to improve it and adapt it to my last needs, taking advantage of the latest Swift versions evolution.

As SwiftUI keeps getting better and more stable, the transition from UIKit to SwiftUI will be inevitable. But until that time comes, this will still be a valid solution for those projects with huge potential for growth in terms of both code size and engineers, which require setting a maintainable and scalable working framework.

What’s next

One of my eternal improvement pending tasks has been to improve the CellBuilder. I’ve tried several and unsuccessfully times to get rid of the iterative task of handling every new CellIdentifier in the huge switch statement. Unfortunately, the result has been always the same: some Swift error warning me about how the approach I had decided to use was too generic to be inferred by the compiler.

At this point, either no Swift feature could fit to get me an answer (yet), or I am not savvy enough to come up with a solution.

The most likely scenario is the second one. So please stop my suffering and help me turn that ugly duckling into a swan once and for all. I’m waiting eagerly for your PRs 🙃

Hope you enjoyed this post! If you did and would like to participate in the challenges we face at Ninety Nine, check our open positions on our careers page https://ninety-nine.jobs.personio.com. We are an international company based in Madrid open to 100% remote candidates.

--

--