MVVM design pattern and RxSwift

MVVM_RxSwift_smallMVVM is a design pattern in software development that separates main application components into three interconnected categories: Model, View and ViewModel. Model represents the data, View represents the user interfaces and ViewModel represents the main link between View and Model.

 

Model

Model represents the data layer of the application. It consists of domain entities/models and the business logic. Model isn’t just your entity structs or a database but also services/components like Alamofire, or Facebook SDK etc…

Model performs all operations on the data e.g. it knows how to get/store/delete/update the data. These operations are initiated by the ViewModel. After Model performs operations on data it notifies ViewModel with the results.

Model is owned by the ViewModel and knows nothing about the View or the ViewModel.

View

View is the visual representation of the application and contains no logic. It consists of user interfaces that receive user interaction events and display data. The user interaction events are forwarded to ViewModel which is responsible to handle them. View observes changes in ViewModel and displays data that ViewModel prepares for presentation.

There is no direct connection between View and Model, they are connected by the ViewModel which is owned by the View.

User interfaces are defined in xibs and storyboards using components that you can find in UIKit, like UIButton, UILabel, UICollectionView etc. The ViewController is directly related to the xib or storyboard where the user interface is defined. It contains outlets of elements defined in xibs or storyboards and contains additional implementation that configures the UI. It also manages the lifecycle events of the View. They are so tightly coupled that in MVVM design pattern, the ViewController is considered to be a part of the View.

ViewModel

ViewModel represents application logic. It handles user interaction from the View and updates the Model. After Model updates, the ViewModel is notified with the results and it prepares the data for presentation in the View. In a trivial example, a ViewModel might request some data from the Model that contains a date. The NSDate value will not be exposed to the View, instead the ViewModel will prepare and format it for presentation as a string using an NSDateFormatter. The View will never manipulate the Model data itself, it will simply display what ViewModel prepares for presentation.

Similar to MVC

In MVC design pattern, View Controller is the glue between the Model and the View. It owns the View, manages the view hierarchy and responds to user interaction. It’s also responsible for the view lifecycle events like loading, appearing, disappearing etc. Another responsibility of the ViewController is to update the Model, and it also contains the presentation logic to display the Model data. All these responsibilities make ViewControllers very large and that is why MVC design pattern is also known as Massive View Controllers.

There are a couple of issues with Massive View Controllers. With all responsibilities a ViewController has to handle, the code is much harder to reason about. It obviously breaks the Single responsibility principle. Testing the application logic contained in the View Controller is very hard to achieve. The ViewController is tightly coupled to the view and it’s lifecycle events which makes the containing application logic very hard to isolate and test. You need to put a lot of effort in mocking the lifecycle events of the view.

MVVM is very similar to MVC. As I mentioned previously, in MVC the ViewController contains both view and application logic. Isolating the application logic of the ViewController and factoring it away into it’s own class using composition pattern, you’re left with ViewController containing only View part of the implementation, and another class that the ViewController owns which contains the application logic. That class is the ViewModel, and it has a 1:1 relationship with ViewController. So MVVM design pattern is basically the MVC design pattern that has application logic isolated from the ViewController and put into the ViewModel using a composition pattern.

Binding data from ViewModel to View

There are many mechanisms that can be used for binding data to view. For example, Swift supports property observers out of the box. View can provide an update closure to ViewModel which can be used to notify the View of any changes to observed properties. Apart from observing changes, an application usually needs to handle some asynchronous operations (like network requests) and streams (like events or notifications). This is a perfect job for a FRP framework. While there are many FRP frameworks available today, the two most popular are RxSwift and ReactiveCocoa. As I wrote in the RxSwift vs ReactiveCocoa blog posts, even though you cannot go wrong with either, I prefer RxSwift.

RxSwift

Imperative paradigm is based on explicit instructions that are executed step by step. They describe exactly how the program works. Values are assigned and stored as state. Since the execution is step by step, if one of the values changes at a later time, the changes are not propagated.

Reactive paradigm, in contrast to imperative, is based on propagation of changes. It is based on declarative programming, which means it focuses on what the program should accomplish, instead how exactly the program works. It does so using mathematical operations and other operators like filter, map, reduce, etc. How exactly the program works is left to the lower levels of a programming language or a framework.

RxSwift allows you to write code using functional reactive programming (FRP) paradigm. You can easily create event or data streams that can be composed, transformed, and finally observed to perform some actions based on observed values.

As mentioned previously, in MVVM pattern View observes Model data prepared by the ViewModel for display. RxSwift provides a simple and clean mechanism of observing these values and binding them to the View.

Observable

Observable is the main building block of RxSwift. It is a sequence that can receive elements asynchrnously. Those sequences can have 0 or more elements. There are three types of events that can occur: Next, Error and Completed.

You can observe these events using the subscribe method of an Observable. That way you can handle each case of the event. On next you can use the element value that is observed. On completed is called when the Observable sequence finished successfully. On error is called if the Observable sequence failed to complete. Once completed or error event is observed, the Observable sequence cannot produced any other element.

Hot and cold observables

Observables are considered hot if they produce elements even if no observers are subscribed. Consider notification center, those will fire even if there are no observers. If you subscribe to that kind of an Observable sequence you might have missed previous notifications.

Observables are considered cold if they produce elements only after observer subscribes. Often the resources are allocated per observer subscription (e.g. each time you subscribe one network request will be fired) but those can be shared (only one network request fired for all subscribers of that Observable).

Driver

Driver is a value type component that is part of RxCocoa. It wraps the Observable sequence and is really just a convenience for easier value binding in the UI. Observables can error out and you need a convenience to display something easily if that happens. Every observable can be converted into a Driver using an asDriver method where you just provide what to return if the underlying observable errors out:

Consider a situation where you want to perform an asynchronous operation, like network request and display the count of results in the UI. You need to map the count of returned items to a string, e.g. the string may be formatted like “X item(s)”. Driver also ensures that subscription happens on a main scheduler since we’re driving the UI.

Now it’s easy to bind that data to a label:

DisposeBag

If a sequence terminates, not calling dispose wan’t cause permanent resource leaks, but those resources will be used until the sequence completes or errors out. If a sequence does not complete or does not error out it will be allocated permanently. This is why it’s convenient to use DisposeBag as a member variable and adding all disposables to it. That way, once your object is deallocated, all resources will be disposed and cleaned up.

Variable

Variables represent a state that can be observed. They are a bridge between stateful and functional paradigms. Variable always contains initial value provided to the constructor and whenever you subscribe the current value will immediately be sent to that subscription (previous values will not be sent, only the latest/current value). You can also get or set the value of the variable through the exposed value property. The underlying observable can be accessed using the asObservable() method. Variable can never error out.

I created an example application written using MVVM design pattern and RxSwift. It’s a simple application that fetches and displays weather data. There are three states of the app: loading (while the network request is performed), displayed data (when request completes successfully the weather data is displayed) and error (when network request fails). There are two variations when error occurs. One is that we just display error, the other is that we show previously fetched data if available, if not then the error is shown. Both variations are implemented using reactive paradigm and imperative paradigm. So you have simple error imperative and reactive, and fallback to old data imperative and reactive implementation.

In these examples only the ViewModel has changed. You can see how by increasing complexity a bit (by showing old data on error) you’re going to have to make more changes with the reactive paradigm to model the change. It is going to be more expressive since it is declarative programming and you can easily follow the chain. Changing the same using imperative paradigm meant just adding additional state, though it is not as expressive.

If you liked this blog post I’d appreciate if you followed me on Twitter

Related Post

Remember to share...Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

2 thoughts on “MVVM design pattern and RxSwift

  1. Nice article. Very easy to read. Just one remark: Can you please share a link for an example application? Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *