Model-View-Viewmodel And Swift
What Is Wrong With Model-View-Controller
Model-View-Controller, or MVC for short, is a widely used design pattern for architecting software applications. Cocoa applications are centered around MVC and many of Apple's frameworks are impregnated by the pattern.
For the past few weeks, I have been working on the next major release of Samsara, a meditation application I have been developing for the past few years. The settings view is an important aspect of the application.
From the perspective of the user, the settings view is nothing more than a collection of controls, labels, and buttons. Under the hood, however, lives a fat view controller that is responsible for managing the content of the table view and the data that is fed to the table view.
Table views are flexible and cleverly designed. A table view asks its data source for the data it needs to present and it delegates user interaction to its delegate. That makes them incredibly reusable. Unfortunately, the more the table view gains in complexity, the more unwiedly the data source becomes.
Table views are a fine example of the MVC pattern in action. The model layer hands the data source (mostly a view controller) the data the view layer (the table view) needs to display. But table views also illustrate how the MVC pattern can fall short. Before we take a closer look at the problem, I'd like to take a brief look at the MVC pattern. What is it? What makes it so popular?
What Is It?
The MVC pattern breaks an application up into three components or layers:
The model layer is responsible for the business logic of the application. It manages the application state. This also includes reading and writing data, persisting application state, and it may even include tasks related to data management, such as networking and data validation.
The view layer has two important tasks:
- presenting data to the user
- handling user interaction
A core principle of the MVC pattern is the view layer's ignorance with respect to the model layer. Views are dumb objects. They only know how to present data to the user. They don't know or understand what they are presenting.
The view and model layers are glued together by one or more controllers. In iOS applications, that glue is a view controller, an instance of the
UIViewController class or a subclass thereof.
A controller knows about the view layer as well as the model layer. This often results in tight coupling, making controllers the least reusable component of an application based on the MVC pattern. The view and model layers don't know about the controller. The controller owns the views and the models it interacts with.
Separation of Concerns
The advantage of the MVC pattern is a clear separation of concerns. Each layer of the MVC pattern is responsible for a clearly defined aspect of the application. In most applications, there is no confusion about what belongs in the view and model layer.
What goes into controllers is often less clear. The result is that controllers are frequently used for everything that doesn't clearly belong in the view or model layer.
Whereas controllers are often not reusable, view and model objects are easy to reuse. If the MVC pattern is correctly implemented, the view layer and model layers should be composed of reusable components.
If you've spent any amount of time reading books or tutorials about iOS or OS X development, then you've probably come across people complaining about the MVC pattern. Why is that? What is wrong with the MVC pattern?
A clear separation of concerns is great. It makes your life as a developer easier. Projects are easier to architect and structure. But that is only part of the story. A lot of the code you write doesn't belong in the view or model layer. No problem. Dump it in the controller. Problem solved. Right? Not really.
Data formatting is a common task. Imagine that you are developing an invoicing application. Each invoice has a creation date. Depending on the locale of the user, the date of an invoice needs to be formatted differently.
The creation date of an invoice is stored in the model layer and the view displays the formatted date. That is obvious. But who is responsible for formatting the date? The model? Maybe. The view? Remember that the view shouldn't need to understand what it is presenting to the user. But why should the model be responsible for a task that is related to the user interface?
Wait a minute. What about our good old controller? Sure. Dump it in the controller. After thousands of lines of code, you end up with a bunch of overweight controllers, ready to burst and impossible to test. Isn't MVC the best thing ever?
How Can We Solve This?
In recent years, another pattern has been gaining traction in the Cocoa community. It is commonly referred to as the Model-View-ViewModel pattern, MVVM for short. The origins of the MVVM pattern lead back to Microsoft and it continues to be used in modern Windows development.
The MVVM pattern introduces a fourth component, the view model. The view model is responsible for managing the model and funneling the model's data to the view via the controller. This is what that looks like.
Despite its name, the MVVM pattern includes four major components:
- View Model
The implementation of a view model is usually straightforward. All it does is translate data from the model to values the view(s) can display. The controller is no longer responsible for this ungrateful task.
Because view models have a close relationship with the models they consume, they are considered more model than view.
MVVM in Practice
Because an example is easier to understand than a theoretical discussion, I will use Samsara as an example to apply the MVVM pattern. The goal is to refactor the settings view of Samsara using MVVM. With the help of MVVM, I plan to end up with a skinny view controller and one or more view models.
Along the way, you'll learn more about the MVVM pattern and how it applies to Cocoa development. You'll also learn how Swift can help us elegantly apply the MVVM pattern thanks to protocols, protocol extensions, and enumerations. Questions? Leave them in the comments below or reach out to me on Twitter.