MVVM + Coordinators + RxSwift and sample iOS application with authentication

Posted on Posted in iOS

Overview

In this article, I’m going to present how to apply MVVM pattern in your application. Later we will extend this solution to use RxSwift and Coordinators.

I also prepared a demo application that shows how to use all of these to implement features like authentication, drawer navigation menu, and localization support. It’s probably worth to analyze Swift MVVM-C demo while reading.

For code samples from this article check out this repository: Swift-MVVMC-SimpleExample

MVVM

Before going further let’s first explain shortly what is MVVM pattern. The name is an abbreviation of Model + View + ViewModel:

MVVM diagram
MVVM diagram
  • Model contains domain objects and data access layer. There can be structures, DTOs, rest client, database client, etc.
  • View is a UI layout designed using selected technology. In our case, it could be xib file, Storyboard or UIView subclass. UIViewController should be also considered as a part of View, because it will be responsible only for setting up controls and notifying ViewModel about user interactions.
  • ViewModel is a connecting layer between View and Model responsible for preparing, loading, updating and formatting Model to be displayed on View. It can use dependencies like database client to fetch or modify Model.

MVVM – rules

  • Model should not be aware of View and ViewModel.
  • ViewModel should be UI independent to ensure testability. It should not refer to UIKit or any classes from View layer. It should communicate with View only through notifications or delegate methods. It can own some objects from Model layer.
  • View owns and notifies ViewModel about all interactions like a button tap, cell tap, slider value change, text field update.
  • View updates its state based on data and notifications from ViewModel.

Secret Glue – bindings

MVVM was invented by John Gossman for WPF (C# framework for Windows desktop apps) which offers rich built-in bindings, making it easy to connect View with ViewModel.

Binding is a mechanism that automatically notifies ViewModel about changes in View (and vice-versa) and updates associated properties. In WPF it can be used like this:
<Label Content="{Binding ViewModel.ErrorMessage}"/>

MVVM has become popular across other technologies, however, its iOS adaptation is a little bit more complicated because of lack of built-in bindings similar to WPF’s.

Fortunately, there are mature 3rd party libraries like RxSwift which help a lot with this task. The drawback is that it requires quite a lot of boilerplate to set up bindings each time. On the other hand, RxSwift makes it easy to add some extra features which would be not possible out of the box in WPF. Like for example debouncing or throttling.

What about business logic?

This might be interpreted in many different ways. By definition, you should consider it as a part of Model. However, some people prefer to see this as a new separate Service layer which is responsible for business logic.

MVVM is not a very strict pattern, so there is nothing wrong in my opinion to call some part of the Model as Services. Actually, MVVM defines the minimum separation of concerns, so another extra layer is fine as well. The main thing is to keep the code SOLID.

MVVM example using delegates

Now you should have a general idea about MVVM, so we can check out some code samples.

MVVM example using RxSwift

In this article, I’m going to skip the introduction to RxSwift, because it’s quite a big topic and not necessary for understanding MVVM-C concept. I can recommend these articles to get started:

Now let’s try implementing the same using RxSwift. A little bit more code, but ViewModel has no explicit reference to delegate, instead, it broadcasts events didFailSignIn and didSignIn.

I’m not a RxSwift guru, so probably it’s possible to do it better :).

Time for Coordinators

Coordinators pattern was invented to separate navigation logic from View and ViewModel and make views reusable. It also makes code more loosely coupled. This approach additionally solves problems like deep navigation when omitting usual flow to display a specific screen is required.

A coordinator is responsible for:

  • Initializing View with ViewModel.
  • Injecting dependencies to ViewModel.
  • Handling navigation flow based on notifications from ViewModel.
  • Passing data between ViewModels.
  • Starting child Coordinators.

Coordinator skeleton

Each Coordinator should implement method start and variable property of type UINavigationViewController which will be used to display flow.

Communication between MVVM and Coordinators

One approach to ensure loosely coupled communication between ViewModel and Coordinator is to inject Coordinator to ViewModel and communicate using delegate methods. Similarly to communication between ViewModel and View.

However, in my opinion, a better approach is to use a power of RxSwift and expose in ViewModel Observables on which Coordinator will subscribe. This way ViewModel is not aware of Coordinator and doesn’t have any reference to it (besides the one hidden within Observable as a subscription).

As you can see, the new Coordinator layer simplified View making it reusable. View is not responsible for navigation anymore, therefore it’s not strictly tied with the specific flow.

Now you can use this screen to show the login screen and to present it modally when the session is expired without disrupting the current application state.

Child coordinators

When application flow gets complicated, it’s a good idea to add child coordinators. In this approach, each small flow has its own Coordinator.

It requires to add some child coordinators management code, we need to implement a BaseCoordinator. Each Coordinator will have to call didFinish method from its parent Coordinator to let know that its work is done and reference can be released.

Coordinators hierarchy example

In my Swift MVVM-C Demo application you can see the following hierarchy of coordinators:

Coordinators

Beauty of MVVM-C

The beauty of MVVM-C pattern is that you can pick which part of it you want to use and you can mix different approaches within a single application. It makes it a good pattern for small apps where you can start up with a simple architecture and when things get complicated you can improve architecture gradually.

You can start with MVC for very simple screens, then when more formatting, backend calls etc. is required, you can extract it to ViewModel. Going further when navigation gets complicated and views reusability is needed, you can implement Coordinator. When things get even more complicated, you can add child coordinators.

Pros of MVVM-C

  • Reusable views.
  • Good separation of concerns.
  • Highly increased testability.
  • Passing data between screens doesn’t cause a strong connection between them, because now the Coordinator is responsible for that and Views/ViewModel don’t know about each other.
  • Storyboards are simplified, don’t have segues. Actually, they can be replaced with xib files.
  • ViewControllers are much smaller.
  • It can be introduced gradually. You can start with MVC architecture and gradually migrate to MVVM then to MVVM-C.

Cons of MVVM-C

  • Usually requires to use RxSwift or something similar to make communication between layers simpler. RxSwift has a quite steep learning curve though.
  • RxSwift is tricky. If you are not careful enough, memory leaks are certain. Anyway, you will need to invest some time in debugging to make sure that everything is released as expected.
  • RxSwift makes debugging harder.
  • Implementation requires quite a lot of boilerplate. You need to create View, ViewModel, Coordinator for each part of your application and bind all together.
  • You can get tired after writing, again and again, binding code for each screen :).
  • ViewModel is usually closely connected with a specific View, therefore it’s not really reusable.
  • Might be worth to read also:

Final thoughts

Remember: you can have a clean code using even MVC, it’s not a bad pattern. Bad is a tendency to put everything into ViewController, but if you follow SOLID principles you can end up with a good piece of code.

MVVM-C is only to give you some guidelines on how to do it. Even if you had never heard about MVVM-C, following SOLID principles you could have ended up with a very similar architecture, but probably without keywords like ViewModel.

In general, architecture should be selected based on project size, requirements, timeline, etc. Each architecture has its own purpose which might be good for one project and bad for another. It’s always worth to consider the pros and cons of each choice and pick the best one fitting your case.