Practical MVVM + RxSwift

Mohammad Zakizadeh
8 min readFeb 11, 2019

--

Today we will implement MVVM design pattern with RxSwift. For those of you who are new to RxSwift, I made an intro part here.

If you think RxSwift is hard or ambiguous, don’t worry. It may seem hard at first but with the examples and practice, it will become simple and understandable.👍

While implementing the MVVM design pattern with RxSwift, we will use all the advantages of this approach in a real project. We will work on a simple app that shows a list of Linkin Park’s albums and songs in the UICollectionView and UITableView (R.I.P Chester🙏). Let’s begin!

App main view

UI Setup

Child View Controllers

I’d love to follow Reusability Principle while building our app. So we will implement our albums CollectionView and songs TableView in a way that we can later reuse these views in other parts of our app. For example, imagine we want to show songs from each album or we have a part that shows similar albums. If we don’t want to implement these parts each time, it’s better to make them reusable.

So what can we do? Child viewControllers to the rescue.
For this we divide UIViewController with the use of ContainerView in 2 parts:

1. AlbumCollectionViewVC
2. TrackTableViewVC

Now the parent viewController consists of two ChildViewControllers (to learn about childViewController you can read this article).

So our main ViewController will become:

We use nib for our cells so we can reuse them easily:

For registering the cells of nib file, you should put this code in viewDidLoad method of AlbumCollectionViewVC class. So the UICollectionView understands what kind of cells it’s using:

Consider that this code should be in AlbumCollectionViewVC class. This means that one of the child’s classes of parent class and the parent class has to do nothing with the objects of its child’s class for now.

For TrackTableViewVC we do the same process with the difference that it is just a table view. Now we’re going to parent class and we should setup our 2 child classes.

As you saw in the storyboard picture, the place of child classes is two views in which our viewControllers are placed. These views are called ContainerView. For setting up these views we can use the following code:

View Model Setup

Basic View Model Architecture

So our Views are ready now we get to ViewModel and RxSwift:

In the home ViewModel class, we should get data from our server and do the parsing in a way that the view exactly wants. Then viewModel gives it to the parent class and the parent class passes those data to the child view controllers. It means that the parent class requests data from its view model and the view model sends a request to the network layer. Then the view model parses the data and gives it to the parent class.

Take a look at the following diagram for better understanding:

The completed project in GitHub is implemented in RxSwift and without Rx. The implementation without Rx is in MVVMWithoutRx branch. In this article, we get through the RxSwift way. Please check without Rx way too, which implemented with closures.

Adding RxSwift

Now here is the exciting part when RxSwift enters🚶‍♂️. Before that, let’s understand what else the view model should give to our class:

  1. Loading(Bool): Whereas we send a request to the server, we should show a loading. So the user understands, something is loading now. For this, we need the Observables of Bool. When it was true it would mean that it is loading and when it was false — it has loaded (if you don’t know what are observables read part1).
  2. Error(homeError): The possible errors from the server and any other errors. It could be pop ups, Internet errors, and … this one should be observables of error type, so that if it had a value, we would show it on the screen.
  3. The collection and table views data ,…

So we have three kinds of Observables that our parent class should be registered to them:

These are our view model class variables. All the four of them are observables and without a first value. Now you may ask: what is PublishSubject?

As we said before, some of the variables are Observer and some of them are Observable. And we have another one that can be both Observer and Observable at the same time, these are called Subjects.

Subjects themselves are divided into 4 parts (explaining each of them, would require another article). But I used PublishSubject in this project, which is the most popular one. If you want to know more about subjects, I recommend reading this article.

One of the good reason for using PublishSubject is that can be initialized without an initial value.

UI to data binding (RxCocoa)

Now let’s get into the code and see how can we can feed data to our view:

Before we get into the view model code, we need to prepare the HomeVC class for observing the viewModel variables and react views from the view model data:

In this code, we are binding loading to isAnimating, which means that whenever viewModel changed loading value, the isAnimating value of our view controllers would change as well. You may ask if we’re showing the loading animation with just that code. The answer is yes but it requires some extension which I’ll explain later on.

In order for our data to bind to UIKit, in favor of RxCocoa, there are so many properties available from different Views that you can access those from rxproperty. These properties are Binders so you can do the bindings easily. What does that mean?

It means whenever we bind an Observable to a binder, the binder reacts to the Observable value. For example, imagine you have PublishSubject of a Bool which produces true and false. If you bind this subject to the isHidden property of a view, the view would be hidden if the publishSubject produces true. If the publishSubject produces false, the view isHidden property would become false and then the view would no longer be hidden. It’s very cool, isn’t it?

Despite that RxCocoa contains lots of UIKit properties thanks to the Rx team, there are some properties (for example custom ones, in our case is Animating) that are not in the RxCocoa but you can add them easily:

Now let’s explain the above code:

  1. First, we wrote an extension to Reactive which is in RxCocoa and affect RX property of UIViewController.
  2. We implement isAnimating variable to UIViewControllers of type Binder<Bool> so that can be bindable.
  3. Next, we create Binder and for the binder part, the closure giving us the view controller (vc) and the value of isAnimating (active). So we are able to say what happens to the viewController in each value of isAnimating, so if active is true, we are showing loading animation with vc.startAnimating() and hide the loading when active is false.

Now our loading is ready to receive data from ViewModel. So let’s get into the other binders:

In the above code, whenever an error comes from the ViewModel, we are subscribed to it. You can do whatever you want with the error (I’m showing a pop up).

So what is the .observeOn(MainScheduler.instance)?🤔 This part of the code is bringing the emitted signals (in our case errors) to the main thread because our ViewModel is sending values from the background thread. So we prevent awkward run time crash because of the background thread. You just bring your signals to the main thread just in one line instead of doing the DispatchQueue.main.async {} way.

Last touch

Connect Albums and Tracks properties

Now let’s do the binding for our UICollectionView and UITableView of albums and tracks. Because our tableView and collectionView properties are in our child ViewControllers. For now, we are just binding array of albums and tracks from ViewModel to tracks and albums properties of childViewControllers and let the child be responsible for showing them (I’ll show how it can be done at the end of article):

Request data from View Model

Now let’s get back to our ViewModel and see what’s happening:

  1. we are emitting loading value to true and because we already do the binding in HomeVC class, our viewController now showing the loading animation.
  2. Next, we are just sending a request for data to the network layer (Alamofire or any network layer you have).
  3. After that, we got the response from the server we should end the loading animation by emitting false to loading.
  4. line (13–19) Now having the response of the server, if we got into trouble, we emit the error value. Again, because the HomeVC has already subscribed to errors, they are shown to the user.
  5. (line 8–11) If the response was successful, we parse the data and emit values of albums and tracks.

Now that our data is ready and we passed to our childViewControllers, finally we should show the data in CollectionView and TableView:

If you remember in HomeVC class:

Now in viewDidLoad method of trackTableViewVC, we should bind tracks to UITableView, which can be done in 2 lines. Thanks to RxCocoa!

Yes, you’re right just 2 lines. No more setting delegate or dataSource, no more numberOfSections, numberOfRowsInSection and cellForRowAt . RxCocoa handles everything in just 2 lines.

You just need to pass the model (binding model to UITableView) and give it a cellType. In the closure, RxCocoa will give you cell, model and the row corresponding to your model array, so that you could feed the cell with the corresponding model. In our cell, whenever the model gets set with didSet, the cell is going to set the properties with the model.

Of course, you could change the view within the closure, but I prefer the computed property way.

Adding bonus animation

Before ending the article, let’s give some life to our tableView and collectionView by giving some animations:

So our implemented project looks like this:

live demo

Final words.

We implemented a simple app in MVVM with the help of RxSwift and RxCocoa. I hope you got more familiar with these concepts. Feel free to comment and share your thoughts on any piece of this guide.

The completed project can be found in GitHub repo here.

Don’t forget to 👏 if you liked the article & project. And you can catch me on Twitter or via email (mohammad_Z74@icloud.com).

Thanks for reading!

--

--