A POP approach for table views using MVVM.

Rohan Bhale
5 min readDec 9, 2017

--

First things first. POP stands for Protocol Oriented Programming. There is plenty of readily available material on POP, so I won’t go into the details of it.
MVVM stands for Model View View Model. It is a design pattern where we have classes or types which could fall into three categories viz Models, Views and View Models. This is a really great article for understanding MVVM. I choose MVVM over MVC(Model View Controller) as MVC often results into monolithic Massive View Controllers.

Now lets start. We first begin by defining a protocol for a tableviewcellmodel. A tableviewcellmodel is going to contain an identifier for the cell. It will also contain additional data to configure a cell. We also need tableviewcell that can be configured with this tableviewcellmodel. So we also define a configurablecell protocol.

protocol RBTableViewCellModel
Source code for protocol RBTableViewCellModel

The RBTableViewCellModel has declared a get only property identifier. This should be used to deque a cell from a tableview. The static demoModel method should be implemented to provide a demo model, which is very helpful for testing purpose. You can see below that I will not use real world data but demo data for demonstration purpose.

protocol RBConfigurableTableViewCell

RBConfigurableTableViewCell has declared a method configure(with:) which should be used to configure a cell with a RBTableViewCellModel.
Now hence forward any UITableViewCell or a subclass that we create should confirm to the RBConfigurableTableViewCell. We will enforce this later by throwing an error in the datasource method for creating cells.

Now that we are done on the cell level lets move onto tableview. A tableview would be represented by a tableviewmodel. So lets define a protocol for a tableviewmodel.

protocol RBTableViewModel

RBTableViewModel enforces a tableview model to implement a two dimensional array of RBTableViewCellModel called cellModels. These cell models will represent the cells in the tableview. It also enforces a type to implement configure(tableView:) which can be used to register cells and any other set up for the tableView.The static demoModel method should be implemented to provide a demo model, which is very helpful for testing purpose. We also extend the protocol to provide default implementations of calculated property numberOfSection and also define two methods numberOfRows(in:) and cellModel(at:) which will return number of rows in section and cell model at the given indexpath respectively.

Now we have defined the view models at the protocol level. This was the first and important step of POP. Now we define concrete types that would implement these protocols. Lets start by creating a cell model type.

struct RBConcreteCellModel

We create a struct RBConcreteCellModel. It defines a static property concreteCellIdentifier for stating a cell identifier. It also defines two String properties text and detailText. We also extend it to coform to RBTableViewCellModel protocol. Here we return the static property as the identifier.

Now lets define a concrete cell.

class RBConcreteCell

Here we created a subclass of UITableViewCell called RBConcreteCell. Then we extend it to conform to RBConfigurableTableViewCell protocol. Then we implement configure(with:) to get it configured. Here we have put in a guard statement that binds the RBConcreteCell with the RBConcreteCellModel model. This is how we achieved a tight binding of a cell model with a cell.

Now lets move on to implementing a concrete tableview model.

struct RBConcreteTableViewModel

Here we have created a struct RBConcreteTableViewModel. This struct conforms to RBTableViewModel protocol. We conform the protocol by providing the properties and functions.

Now lets create a UITableViewController subclass and use our view models for filling up content in the table view.

class RBConcreteTableViewController

Here whatever framework we layed out using POP comes to fruition with a very clean datasource for the tableview. We create RBConcreteTableViewController which is a subclass of UITableViewController. It has a property tableViewModel of type RBTableViewModel, which means it can use any type that conforms to RBTableViewModel. We override viewDidLoad() to configure the tableView with the tableViewModel. Then we have the boilerplate code for UITableViewDatasource methods. As you can see the code is much cleaner. You can track errors earlier. We also avoided a very massive view controller.

This code can be improved for consistency purpose by creating a protocol for a configurable table view, but you can do that easily by following the template for a configurable cell protocol above. The source code for this POP approach is available here. You can go ahead and improve the implementation for your own use.

Did you enjoy this article? Perhaps try one of these:

Please do provide any feedback for improvements. My TapChief profile is as below:

--

--