MVVM in iOS
Lately there has been a lot of talk about MVVM in iOS applications and how it can help to tame the symptoms of massive view controllers. The default architecture pattern for building iOS applications is MVC (Model View Controller) and although there is nothing wrong with MVC pattern, but most of the time view controller becomes the point of code dumping ground.
MVVM is not something new that just popped out of nowhere, it has been used for several years specially in the .NET community. I have worked on many large scale WPF (Windows Presentation Foundation) applications where MVVM was used successfully.
Having said that comparing .NET WPF framework to iOS framework is not fair because WPF uses XAML and the power of “Dependency Properties” to perform two way seamless binding. In iOS we don’t have anything similar to dependency properties and even if we had we don’t have declarative UI code like XAML.
The idea behind MVVM pattern is that each View on the screen will be backed by a View Model that represents the data for the view. This means if we are building a News application then the view might consists of a UITableView which allows to display the news items and the view model will consists of the data representing the news item like title, description, publishedDate, author, source etc.
A sample view is shown below. It consists of a simple UITableView control, which uses the default UITableView cell for display.
Now, think about what data you want to display in the view. For sake of simplicity we will display title and description. So, view model will consists of properties that can provide the title and the description.
Our first implementation might look something like this:
This certainly represents the data that we want to display in the UITableView but it does have few short comings. It only represents the part of the view that can be populated. The view model should be able to accommodate the complete view. Check out the implementation below:
By adding a parent view model “ArticleListViewModel” we have created more flexibility to control the items on the screen. If in the future we need to add a search bar then we can simply add a reference to the SearchViewModel inside our ArticleListViewModel.
View Models + Networking = ?
While researching on the MVVM implementations in iOS I came across a lot of resources where the developer implemented the networking code and data access code right inside the view model. One of the possible implementations is shown below:
Your view model should be as dumb as possible. It should not contain networking code or data access code. When you start performing networking operations inside view model you are adding tight coupling between the view model layer and the web services layer.
UPDATE: As few readers pointed out that It is not fair for me to say that your view model should not invoke web services as Microsoft, who has been using MVVM architecture for a long time does seem to advocate the idea of calling web services from right inside the view model.
Even in the iOS community I have seen developers using different flavors of MVVM architecture. I would encourage you to choose the MVVM architecture that best fits your needs.
Networking and data access operations should be isolated from the view models and should be part of separate classes or even separate framework/library. Depending on your application, networking and data access operations can be passed into the view controller constructor as dependency injections.
Here is an implementation of a web service call that happens inside the view controller but controlled by a separate web service class.
The web service returns the domain objects which is then mapped to the view model objects. This mapping can be performed manually or using any iOS auto mapping tool similar to AutoMapper in .NET.
Finally, when the mapping is done we set our view model which triggers the UITableView reload. This trigger happens automatically because of the didSet property behavior. Keep in mind that didSet will not get fired when the properties are set inside the constructor of the class.
Binding refers to the flow of information between the views and the view models. Consider a scenario where you have to create a registration screen. As you type the information in the text field it is also being populated on a RegistrationViewModel object … instantly. In other words you don’t have to type the following code:
Binding goes both ways! This means if you change your view model properties then it is reflected on the view. This is also known as two-way binding. As I mentioned earlier that in WPF framework, binding is handled by dependency properties. Unfortunately, Swift does not have any dependency properties so we will have to do some work to get this working.
We cannot put an observer on a String type, this means we will create our custom class and allow it to be observed.
Dynamic<T> is a custom class that can hold a value of type T. If the value changes then we fire the didSet, which calls the bind function passing the value back to the caller. The implementation is shown below:
This will setup one-directional binding from view model to the user interface elements. This means if the properties of view model changes then the user interface elements are notified.
In order to create a bi-directional binding you will need to implement a custom UITextField control. This is implemented below:
We attached the editingChanged event to the UITextField and then trigger a custom callback function. Now, you can update our IBOutlets to make use of this new bind function as shown below:
Not pretty but it works!
This is just a very introductory look at the MVVM model. I believe that MVVM approach in iOS can greatly improve if Swift allows the capability of making custom atrributes. This will allow us to create dynamic validation frameworks where each view model can easily validate and return broken rules associated with the view.
As Michael Long pointed out in the comments, MVVM makes it easy to test the logic behind the views.
Another benefit of moving your ViewController’s business logic into your ViewModel is that the viewModel it then becomes a lot easier to create unit tests for those components of your application.
You can download the code here: