FDS: Abstraction of UITableViewDataSource

UITableView’s are a tremendously important part of UIKit that, as any self-taught iOS developer can attest to, is included and emphasized in pretty much every online course. For good reason too — you’d be hard-pressed to find any app out there on the app store that doesn’t list some type of object relevant to the user. Because of how ubiquitous Tables are, I’m sure most people reading this blog post will be familiar with the following paradigm:

Suppose we want to display a list of users. Our users only have a name, and we want to use our UserTableViewCell that has a nameLabel. We define ViewController below.

class ViewController: UIViewController {
  var users: [User]?
  @IBOutlet var tableView: UITableView!

  override func viewDidLoad() {
    // set delegates, datasource to self
    getUsers()
  }

  func getUsers() {
    // get users somehow, set to users
  }
}

We get our users in viewDidLoad, and then at some point after that we reload our tableView.

Next we extend our ViewController to implement UITableViewDataSource and UITableViewDelegate.

extension ViewController: UITableViewDataSource,    
                             UITableViewDelegate {

  override func tableView(_ tableView: UITableView,  
                          cellForRowAt indexPath: IndexPath) 
                               -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(
                       withIdentifier: "myIdentifier") 
                       as? UserTableViewCell else { 
        return UITableViewCell() 
    }
    cell.nameLabel.text = users[indexPath.row].name
    return cell
  }

}

Since I started learning iOS Development, I have probably had to do this process 100 times, yet had never thought to look at the processes herein that are repeated over and over again:

  • Either registering my cell as a nib or giving it an identifier in my storyboard
  • Dequeueing your cell from the tableView
  • Doing some type of styling and populating of the cell based on what model I’m listing

If you look at the code above, you’ll see that only one line (the one where we set the cell’s nameLabel isn’t generalizable.

Which brings us to FlexDataSource, a publicly available CocoaPod that takes care of the repeatable code above. Let’s take a look at the underlying ADTs within this module.

FlexDataSourceItem

A FlexDataSourceItem has three functions — one that returns the cell identifier, one that returns the cell class, and one that configures the cell. Keep in mind, however, that this is a protocol, and at first glance it may be hard to see where the variability in the objects to be listed lies, but subsequent implementations of this protocol will account for this.

FlexDataSourceSection

The FlexDataSourceSection is pretty simple, and acts only as a holder for an array of FlexDataSourceItems. You can view this as analogous to keeping a 2D array of models, one array for each section of the tableView.

FlexDataSourceProtocol

FlexDataSourceProtocol specifies a tableView and an array of FlexDataSourceSection‘s. The protocol also has an extension below with some helper functions, but hopefully you can see how we get from this infrastructure, holding on to the tableView and sections, to a tableView on the phone’s screen displaying sections of data. Here is the extension:

We can see now how the data for each FlexDataSourceItem is used:

  1. Get the name of the cell’s class
  2. If there is a nib file matching that cell’s class, register it with the tableView
  3. If not, register the cell’s class with the tableView under the identifier returned by the required method.

We can also see how the tableView configures each cell:

  1. Make sure that indexPath leads to a stored FlexDataSourceItem
  2. Dequeue the cell from the tableView (if registerCells has already run, this will always work
  3. Configure the cell using the FlexDataSourceItem specified by the indexPath

Now, say we want to make a tableView that has 3 sections: one of all blue cells, one of all red cells, one of all green cells. The normal UITableViewDataSource methods would be complicated, switching on the section of the given indexPath and setting the background color depending on it. With FDS, we can do it the following way:

And then we can make the same ones for blue and green. Then we can construct a FlexDataSourceSection comprised of as many RedItems we want in the section, and do the same for BlueItems and GreenItems, construct a FlexDataSource from that, and assign our UIViewController‘s tableView to it in its viewDidLoad. There is no pesky extension where you have to do the same thing every single time, and the only classes you’re interacting with are the ones that control what cell you are displaying and how you want to configure that cell. It’s not initially obvious how much time that saves you, because switching on a section number and setting the background color is a pretty simple example. In Part 2, we will look at a useful child class of FlexDataSourceItem and integrate it with FunNet — a networking library that I have talked about here.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: