Complex table view state changes made automatically

Ivan Kupalov
6 min readAug 20, 2016

This is not my programming blog but I cannot resist making this post. I would like to help iOS programmers who are dealing with complex (especially dynamic) table view layouts. I also love Kitchen Stories app and I was glad to see a post made by them on iOS development. The way they did their login screen seems great to me. There’s room for improvement, though.

Dealing with dynamic layouts can be hard. That’s why technologies like Reactive Functional Programming (or FRP) were invented. If you don’t know what FRP is I recommend that you look at the great talk by Ash Furrow first. The basic idea is that you define everything in form of a stream of values called Observable. It can contain anything: text inputted by user, response from API, notification. You write code by combining and binding these observables.

One of the cases of these hard layouts is dynamic table views. The nasty thing about them is that the table has state. It means that if you want to make changes to the table (and you want these changes to look neat), you have to manually delete and insert rows and sections. Imagine you have many states of your table. You have to specify insertions and deletions for every transition between states. Yikes.

Kitchen stories made the right decision and used a library which helps them to calculate difference between two states automatically. One of the things that stroke me most is that they already defined their states declarative but still operate on their views in imperative style. But why not take a step further? Why do we have to write all these deleteRowsAtIndexPath’s?

I am going to implement a solution with the power of RxSwift and RxDataSources. The first one is an implementation of FRP in Swift and the second one is the library to do complex things with your table views and collection views.

Example from RxDataSources GitHub

Show me the code!

Ok, first of all, let’s make a table view show something. It would be easier if we wanted to just show same data but in this case we have to animate it so we will have to write a little bit of boilerplate to define our sections.

We define out cells and sections. Out sections will be identified by integers and will contain AuthCell’s. IdentifiableType impementation is requried by RxDataSources so the library can calculate table changes.

Next, I created table view and cells. You’re free to not use storyboards, I just used it for the simplicity’s sake.

Time to get our hands dirty!

Quite a lot asks for an explanation here! First of all, you may ask yourself “What is DisposeBag?”. It is quite a convenient thing that lets us store all our reactive stuff and dispose it with the controller.

I was quite lazy to write function for cell height so I just let cells size themselves.

Now fun begins. We create dataSource which will work with AuthSection’s. We tell it how to create cells. It’s quite easy in our case: we just decode cell. In case we needed to set some data to the cell it would go here.

And, in the end, there’s a little bit of functional magic. We create Observable, very simple one: it will just emit our cells and complete. Map function transforms one data to another. In this case we transform what is carried by the Observable. You can think of it as of assembly line where we transformed our cells into sections. In this simple case we just created one section.

After that we bind our sections to the table view. There’s some dark magic with carried functions going on under the hood but you don’t have to understand it.

And we can hit “Run”!

Yay, it works! We still didn’t change tableView but we are really close, I promise. What we want to do now is to 1) define states of our table view, 2) have a method to switch between them, 3) bind state to our representation. Let’s do it, it’s quite easy! First, states.

We defined two states for our login screen and defined computed property cells which will tell us which cells table view should contain. Now we need to know which state screen has at any moment of time.

“What is this Variable thing?” you may ask. Well, it’s just like a regular variable but it is quite special because it can emit observable items when its value changes. So, when its value changes, our table view will automatically update. Cool, huh? We also created a button which we will put in the footer of our table view. It will change between login and sign up states. Now we have to make our button work. If you think of addTarget(), then don’t (selectors, ew). There’s a better solution.

What’s going on here? Every time our footer button is tapped we want to check what is the current state, emit new state and, finally, apply it. It looks a little bit longer because rx_tap is a ControlEvent and we want to stick to simple Observables for now, that’s why we need to call asObservable(). Same story with the ScreenState variable.

I am not going to describe how to put the button in the table view footer, we have something more fun to do: we have to display current state. There’s almost nothing to be done to achieve this!

Yes, we just changed our Observable.just() to screenState.asObservable().map(). First we get cells for our state and then we just put them into the section like we did. We could do it in one map but I think this way it’s cleaner. Let’s check if it works!

Looks like it does! But wait, animations are not the ones we want. Let’s fix it.

Looks way better. We also want to show the correct button title so let’s do it as well to sharpen our reactive skills.

Not much. Just another property in our enum and one more binding.

Yay, it works! Congrats, we made it. There’s one great thing about defining your states in enum: if you add more states, you will have to change your variables definitions too and you won’t miss anything.

There’s a lot of things you can do here. We didn’t change sign up/login button title, it’s probably should be done using associated value so our enum cannot have raw values anymore. I also would use Drivers instead of Observables in the real-world application (it is a special Observable for developing UI, you can read about them here). Also, you can implement on-the-fly form validation and enable/disable button accordingly. It is quite an easy task to do with FRP!

Rx may seems like an overkill for this simple tutorial but I can assure you that I was making very complex table view with many changes and I was failing until I used RxDataSources. It is quite powerful thing to have in your arsenal.

Hope you enjoyed this tutorial and won’t be afraid to use FRP. You need some time to get used to it but as you get better you learn how to use this black magic.

You can get source code here.

If you’re interested in more tutorials check out RxSwift repository, ReactiveX website, one great visualisation tool and one super awesome blog. Also I would be glad to hear questions or advices here or on my twitter.

--

--

Ivan Kupalov

Android Developer, awareness lover, Function Reactive Programming monk. Fast and curious.