POP III — Simplifying UITableView with different types of cells

Mohammed Imthathullah
4 min readNov 20, 2019

--

This is the third part of the Power of Protocols series. We’ve earlier discussed responding to theme changes and removing network layer in your iOS app.

All the table views in your iOS app has a lot of code repetition. You have to write the DataSource and Delegate methods for each one of them. Add to that the problem of using different types of cells in a single table view, boiler plate code increases and some optional chaining/unsafe types might also creep up. Lets discuss an easy way to abstract all these and focus on making your table views awesome.

TableViews being used all through the iOS. PC: Apple

In general, when you have a table view with multiple sections, the following are some of the methods you need to implement in your table view data source and delegate.

Some often used data-source and delegate methods

Most of your view controllers which contain your table view, most likely will only have the table view. So a better option in that case is to use a UITableViewController which will have a default implementation for most of the methods and override only the functions you want to change.

But lets take a step further and provide structure to our dataSource such that we need to write these functions only once and it will work for most kinds of table views.

class SectionItem {
let id: String
var header: String?
var items: [RowItem]

init(id: String, header: String?, items: [RowItem]) {
self.id = id
self.header = header
self.items = items
}
}

protocol RowItem {

var height: CGFloat { get }

func getCell(at indexPath: IndexPath,
of tableView: UITableView) -> UITableViewCell

func didSelect(at indexPath: IndexPath)
}

Here, the RowItem protocol is a simple abstraction of the most common functions in the delegate and dataSource . To write even less code in creating subsequent table views, you can provide some default implementation for the protocol like below.

extension RowItem {

var height: CGFloat { return UITableView.automaticDimension }

func didSelect(at indexPath: IndexPath) { }
}

You can also use a struct instead of a class for SectionItem . I prefer classes so that I can just pass them around without worrying about memory. This comes with a drawback of requiring to be extra careful about making unintended changes to the object. But I’m cool with it.

The id property in the SectionItem will be helpful in cases where we need to make changes to the rows in a section or the header.

Now, let us subclass UITableViewController and override some dataSource and delegate functions using an array of our type SectionItem as a stored property which acts as the dataSource .

Table View Controller with section items

That’s all you need. Now you can create multiple table views by just subclassing our MITableViewController and setting value for the sections array. You can either set the array while the TableViewController is initialized or update the property at a later time, but do remember to call tableView.reloadData() in that case.

Let me illustrate to you the usage of both cases with examples, continuing from where we left off in the previous post.

First let us initialize the Posts view controller, with an array of posts fetched from the sample API.

PostsViewController

Yup! That’s it. That’s all the code you need for a table view. We’ve confirmed Post to RowItem and added a section with all the posts. Just wire the presentation of this PostsViewController with a button click and you will see the magic.

Now, let us move to presenting albums by fetching it from the server after the view controller is loaded.

AlbumsViewController

Notice the tableView.reloadData() after appending the section. That will call all the required delegate and dataSource methods and the tableView will be updated properly with album titles. You can just present with AlbumsViewController and the data will be updated from the API.

Apart from making your code concise, which is only what I have demonstrated, providing a proper structure to your dataSource using the SectionItem and representing each row using the RowItem protocol gives you unparalleled flexibility with your table views.

Do you want multiple sections each with a different type of cell? Check. Do you want different types of cells within a single section? Check.

All these can be achieved by just appending the SectionItem array in your MITableViewController subclass. And there’s no need to cast types or unwrap optionals. That’s the type safety which the protocols offer.

To work with these swifty table views, you can just copy this file to your project. Here’s the demo if you want to have a look around.

Happy Coding!

--

--

Mohammed Imthathullah

Aspiring Author. Mostly writes code and sometimes articles. Tweets @imthath_m