FDS: FlexModelItems and FunNet (pt 2)

In the last blog post, I took a deep-dive into the basics of FlexDataSource, an extremely useful tool to quickly configure a relationship between models and UITableViewCells, and a relationship between an array of models and a functioning UITableView. As a quick sidebar, I just want to note that FlexDataSource also works with UICollectionViews much in the same way that I’ve explained in the last post. Although I’ve explained why FlexDataSource is useful, I’ve yet to show why it’s flexible with regards to an arbitrary model to be displayed. That is where the FlexModelItem class comes into play. Here it is:

FlexModelItem is generic with two parameters:

  • T: The model we want to populate the cell with (no restrictions)
  • C: The cell we want to be populated (must inherit from UITableViewCell)

FlexModelItem inherits from FlexDataSourceItem, so we know that we can plug in a FlexModelItem whenever a FlexDataSourceItem is used and not lose any functionality. FlexModelItem takes a model and a configurer in its constructor. The configurer is a function that will populate whatever cell type C is with respect to your model of type T. This obviates the need to define your own subclasses of FlexDataSourceItem every time that you have a model-to-cell relationship. The FlexDataSourceItem protocol isn’t generic, however, and FlexDataSource uses the configureCell: (UITableViewCell) -> Void function to populate the cell and a certain indexPath, so we niftily use the *-> operator, defined here, that essentially fixes the first parameter of a two parameter function and returns a function that only depends on the second parameter. In this case, we fix model: T to our configurer: (T, C) -> Void and set the resulting function (C) -> Void to our local variable to save. Then, in our overridden configureCell function, we optionally cast our UITableViewCell to C, and call our configurer on that cell.

Now, as an example, let’s say we have a network call that is supposed to return an array of Users, each with a firstName, lastName, and occupation. We also have a subclass of UITableViewCell called UserTableViewCell that has a nameLabel and an occupationLabel. Now, we want to display a UITableView of all the users that get returned from our network call.

We first define our UsersViewController below:

In our viewDidLoad, we have to set up our dataSource. We have also declared an indicatingCall that we need to store in our UsersViewController so it doesn’t get deallocated. For those who want to read about the network layer that I normally use, please do so here, but for all intents and purposes, a CombineNetCall holds all the data you need for a network call:

  • The URL
  • HTTP Method
  • HTTP Headers
  • URL Parameters
  • HTTP Body

A CombineNetCall also has a fire method that essentially makes a URLSessionDataTask and resumes it as you would using Swift’s native network layer. It also has publishers for the HTTPURLResponse, Error, and Data that you would tap into in the callback of URLSessionDataTask.

Our next step is to create our network call. Elsewhere in our project we define usersIndexNetCall:

What we’ve done here is set up a network call to GET https://example.com/api/v1/users, and we stub our network call with an array of users defined below:

Now, let’s define a function in our ViewController called setUpNetCall that takes in a CombineNetCall and returns an AnyPublisher<FlexDataSource, Never>:

This function stores the call, and taps into the call’s $data publisher and uses a function called modelPublisher that will automatically decode the data publisher’s value into the value-type of the variable, in this case, [User]. Next we use the -*> operator (similar to *->, just with the second parameter instead of the first) and the constructor of FlexModelItem to create a function that maps a User to a FlexModelItem. Then, we use the free-function version of map, and the modelPub‘s map method to create a publisher of [FlexDataSourceItem], and use build-in methods from FDS to create a FlexDataSource publisher, which we return.

Lastly, all we need to do now is get our network call, create the FlexDataSource publisher, sink into it and set it to our dataSource variable, which will then trigger it’s didSet and set itself as our tableView‘s dataSource and reload the tableView.

There — we did it! If you’re following along in this tutorial, you’ll notice that your UIViewController only has one method defined inside of it, besides viewDidLoad. And the cool thing is — no matter how complicated your models become, displaying a list of them is exactly the same process. All of the meat of your programming work goes into the configuring functions that populate your cell’s with your model. Building a UIViewController that makes a call to your backend, decodes it into your model, saves the models, and displays them in a UITableView, with regular, out of the box, Swift would take much longer and require much more lines of code. I’ve gone a long time without conforming a UIViewController to UITableViewDataSource, and this is why. In my next post we’ll build off of this and integrate fuikit, another library I use everyday, so you can see why my UIViewControllers never conform to UITableViewDelegate either.

Happy Coding!

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 )

Facebook photo

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

Connecting to %s

%d bloggers like this: