Using first-class type objects to create UITableViews with multiple cell types

Andrey Volodin
4 min readMay 29, 2018

Problem

When you work for AI company, you always do a lot of technical demos to play with a certain technology in the wild. Modern algorithms tend to have quite a lot of parameters you would want to experiment with and sometimes the result of the work can only be approved by human, especially when it is related to any kind of image processing/computer vision or AR/ML type of apps, where you have to check results with your eyes.

This often leads to the situation where you have to create a bunch of on-screen buttons/sliders so that you can parameterize core logic and see how new hyper-parameters affects the result. After a handful of such demos I decided to create a custom debug menu, where you can add several options in a declarative way and then observe changes.

I made a prototype in a day by forking an existing debug tool Dotzu. Project is still in a beginning stage, but it more or less fits my needs for now. You can play with it in a public repo. Below is the small demo of achieved results:

Implementation

In this small tutorial I’m going to show you a technique which I used to achieve dynamic cell type evaluation in a single UITableView. What I wanted to achieve is that I could create an array of Option objects all of which conforms to a single protocol. This array basically will be an array of models. Then I want my make my table view controller to understand what type of cell (view) it has to use for it representation. I also wanted to avoid using enums, switch, or long conditional chaining (if-else), so that it will be extensible from outside and adding new type of options wouldn’t require rewriting existing library/controller code. Another goal is to encapsulate configuration code for every cell inside its class definition to move it outside of controller.

I started with declaring a protocol for our options. Since it is a 1-day prototype I didn’t put too much of a thought into this protocol, since I’m not quite sure about whole design, but for now let’s require every option to have a name. It also should probably have an associatedtype, but let’s keep it simple for now.

Next, let’s declare a protocol for cells that can represent an option: OptionCell. It also a dead-easy protocol which basically requires an object to know how to configure itself for an option.

Alright, as we now have all needed protocols, let’s create first option type and corresponding cell view. We will start with BoolOption which is often used for feature-toggling.

BoolOptionCell.xib

Now, the interesting part. We create a UITableViewController subclass with no cell prototype in its storyboard:

UserOptions.storyboard

All the magic goes into its implementation. Let’s go through:

  1. At the very bottom we declare an array of models to be presented
  2. Here is the most interesting part. Since first-class type objects are not comparable, we use ObjectIdentifier struct from Swift standard library to create Hashable/Equatable proxy object for each Type object. We declare a dictionary and two handy methods to register and obtain types from it.

Since it is a repetetive code part, it should probably be moved into separate class called TypeRegister or something like that.

3. In viewDidLoad() method we register cell types into table view using a small helper method.

4. Next we register associative Model-View pairs into our type dictionary.

5. In a cellForRowAt: we get a model from our array, determine a cell type for it and dequeue a cell of appropriate type.

6. Finally, we tell UITableView to use Auto-Layout to calculate height of cells, since it can very from one option to another.

That’s it! Now you have super-flexible 60 lines of code implementation of UITableView, that can handle unlimited amount of models in it.

Usage

Usage of the framework is super easy. All you have to do is to initialize debug menu once (usually in AppDelegate) by calling one method:

DebugMenu.sharedManager.enable()

And then declare your options in a declarative manner (usually in controller’s viewDidLoad):

The result of this call can be seen on the video in the beginning of the story

Since the repo is dedicated for debug purposes, you probably would want to cover all interactions with DebugMenu with #if DEBUG … #endif clauses.

Final words

Since UI engineering is not what I do on daily-basis I would love to hear your feedback on the technique and to hear any directions on how to do it even better. Hope you enjoyed the read!

Don’t forget to play with the repo on GitHub and follow me on twitter.

--

--

Andrey Volodin

Professionally bad at UIKit. Leading mobile development at @PrismaAI . ex @cocos2d