How To Never Have to Track a UITableView’s IndexPath Ever Again

Index out of range, no more

How To Never Have to Track a UITableView’s IndexPath Ever Again
Photo by Thought Catalog on Unsplash

How many times have you had to deal with the hassles of manually tracking IndexPaths for a UITableView? Or, how many times have you had to debug this before?Invalid update: invalid number of rows in section...

What if there was a way to take the hassle out of managing this?


Introducing View Model-Driven UITableViews

Each UITableViewCell has its own Equatable view model that’s passed to it on setup. Here’s a simple example for a header cell that takes in a label containing a title and sets it on the cell.Helpful tip: The view model's equatable function doesn't need to be implemented if all the properties in the struct are Equatable.

A UITableViewCell that takes in an Equable view model struct and sets it up

As we build up a list of view models to display onscreen, we may want to support more than one type. In this case, we can take advantage of enums with associated values.

In this example, I have two cells I want to display. Therefore, I use two enums to represent each cell. The associated value contains the equatable view model.

Equatable enum to represent each cell that will be displayed in the UITableView

We can then create our view models either from our controller if we’re using MVC, or a presenter if we’re using MVP. Obviously, this will vary based on the architecture of your app. In our case, we’re calling a function on our UIViewController from our presenter to provide it the data once it’s loaded.

A function that creates and sets the view’s view models

We’ll then need to implement the reloadTableView(..) function. This takes a snapshot of the current view models, updates it to be the new view models, and calls a function that we add via an extension on the UITableView.

Reload function on the UIViewController to reload the UI.

The reloadWithAnimation function called on the tableView can be added into your project using the following file:

aduuub/uitableviewdataflowtutorial

You don’t need to understand the workings of the extension, but it essentially differentiates the difference between the current snapshot and new view models and then inserts, updates, and reloads the view appropriately.


Implementing UITableViewDataSource

For the number of rows in the section, we can simply return the number of view models in the array.

The UITableViewDataSource implementation for numberOfRowsInSection

Now, when we dequeue the cell, we don’t need to worry what index it’s for as it’s entirely driven from the view model. We’ve also prevented the accidental fall through that would default to an empty UITableViewCell being returned. Note that the dequeueCell function is a custom extension you can add to your project here. Alternatively, you can use the standard tableView dequeueCell.

The UITableViewDataSource implementation for cellForRowAt

As for handling tap events, we can easily switch based on the selected IndexPath to determine the corresponding view model.

The UITableViewDelegate implementation for didSelectRowAt

Multiple sections

Easy! All you need to do is make the view model array 2D. The first array represents the sections, and the inner array represents the rows in the section. The reloadTableViewWithAnimation has two implementations that support either approach.


Demo

The following example is from a learn to drive application I recently created. I simply move the item from one section to another or remove it entirely. This uses the RowAnimation.fade as demonstrated in the article with custom deletion logic.

Removing an item from the view models

Want to Just See the Project?

You can check out the project with all the code on my Github below.

aduuub/uitableviewdataflowtutorial
How many times have you had to deal with the hassles of manually tracking IndexPath's for a UITableView? Or had an…

Subscribe to Aniseed Apps - iOS Blog

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe