MVC vs MVVM in iOS (with examples)

Practical ways to implement MVC and MVVM.

A design pattern. But not the kind we’re discussing today. (Photo by 贝莉儿 DANIST on Unsplash)

Introduction

The Model-View-Controller (MVC) design pattern is arguably one of the most widely used patterns in iOS app development. However, with the introduction of SwiftUI and the Combine framework during WWDC19, we may see a shift towards the adoption of Model-View-View Model (MVVM) in the coming years.

You may have read a few articles stating the benefits and disadvantages of these patterns, but I’ll be taking a more practical approach by walking you through how to build an app using each of these patterns.

What are we building?

Everyone loves animals (especially cats) and some of us may have too many pets to keep track of them. To be a responsible pet owner, we will implement our very own PetManager application!

Before we get started, I’ll explain a little about each pattern so we know what we’re implementing. After we’ve implemented the app, we can also see how the classes map to each component in the MVC or MVVM pattern. If you already know your stuff, feel free to head right down to the “Implementing the Pet Manager” section to get started on the app.

What is MVC?

MVC Architecture

Model: Contains the data-related logic. In our case, it’s the representation of our pets.

View: Handles user interactions and displays data to the user. In our case, it is the UI elements like list items that will display our pets’ names and breeds.

Controller: The interface between Model and View. It updates both models and views. In our case, the controller would be responsible for actions like adding or deleting a pet.

In the traditional MVC, the Controller is the entry point of the application for the user. However, considering how tightly coupled Views and Controllers are in iOS (every storyboard ViewController has to be attached to a controller class). Most iOS developers end up implementing a Model-View Adapter (MVA) pattern without even realising it.

The model, view and controller in MVA has the same definition as MVC but all communication goes through the controller (adapter) as shown below. Think of it as an overly-controlling ̶g̶i̶r̶l̶f̶r̶i̶e̶n̶d̶ boss who wants everything to go through them.

MVA Architecture

I know the article states MVC vs MVVM but honestly, everyone thinks that MVA is just MVC so we’ll refer to it as MVC in this article. If you’ve noticed, in the MVA, the controller literally controls everything. It has too many responsibilities and that’s why some people call it the Massive-View-Controller as well.

So how can we separate the Model, View and Controller without giving the controller too many responsibilities? Let’s take a look at the next pattern.

What is MVVM?

The term MVVM was first coined by John Gossman, one of Microsoft’s Windows Presentation Foundation (WPF) architects. It is a specialisation of another pattern called the Presentation Model (PM) which was developed by Martin Fowler. You can read more about PM here.

MVVM Architecture (adapted)

Model: Same as in MVC

View: Same as in MVC

ViewModel: Connects the Model to the View using Bindings (we’ll talk more about this when we implement the app but it’s basically how the View “passes” user interactions to the ViewModel

The diagram above is slightly different from what you would find in the original Microsoft article regarding MVVM. I felt that showing the ownership of the entities would help you to understand how this pattern differs from the MVC (or MVA). From the diagram, we can see that the main difference is that the ViewModel no longer has any reference to the View and the Model has no reference to the ViewModel as well. Each entity can exist on its own and that sounds like good testability to me.

Implementing the PetManager

We will use UIKit in implementing the MVC version of this app. On the other hand, for the MVVM version, although the Combine framework is great, I’d rather not go into the details of it in this tutorial. As SwiftUI has some pretty neat inbuilt features, we’ll use those to implement the MVVM version of the app.

You can download the application from https://github.com/wilfredbtan/PetManager and checkout to the “mvc-mvvm” branch.

The directory contains a UIKit implementation (MVC) and a SwiftUI implementation (MVVM). Let’s take a look at the classes involved and their corresponding role in each pattern.

Here’s a screenshot of what app for the MVC (left) and MVVM (right) version looks like:

Source: Honestly, who knows the source of these memes. Edited by: Me

As you can tell, there’s not much difference in how the app looks. But the magic happens when you look deeper.

Let’s take a look at the MVVM version:

Most of the MVVM magic is possible because of the @ObservedObject and @Published property wrappers. The Model which is wrapped in the ViewModel is a @Published object. Thus, if there are any updates to the model, it will publish a notification to all views observing it. However, it does not do so directly but the ViewModel which is the @ObservedObject will publish the change and the Views will re-render themselves accordingly with the updated data.

Next, let’s see how the MVC version works:

In the MVC version, the controller updates both the Model and “notifies” the view to update accordingly.

In both versions, the Model is similar:

You’ve probably noticed that we can only add Cat objects not any other kind of pet. Other than the fact that I’m biased towards cats, we’ll talk more about how to solve this issue this later.

For now, let’s see what happens when I delete Coby the Persian:

MVVM:

  1. User taps on delete (User Interaction)
  2. View calls viewModel.remove()
  3. ViewModel calls model.remove()
  4. Model removes Coby
  5. Since Model is @Published in the ViewModel, views are informed of the update in state (Notify)
  6. View re-renders itself with the new pets (with Coby removed)

MVC

  1. User taps on delete (User Interaction)
  2. Controller calls model.remove() (Update Data)
  3. Controller deletes the respective row from the table (Update GUI)
TextField("Enter Name", text: $newName)    .textFieldStyle(RoundedBorderTextFieldStyle())    .padding()

You may have noticed that the “Data Binding” portion of MVVM is missing in our implementation. However, that is actually displayed in the use of the TextField to enter your name (using the $newName property). the “$” binds the newName variable to the user input internally. Since there are no controllers telling the view how to update when users key in their input, they have to bind their values to a certain state. In the code example, we bind the first TextField to newName so that whenever the user types into the TextField, the newName state is updated with a new value and displays what the user is typing onto the screen.

Also, I didn’t implement this in our code example but if the model gets updated directly, MVC and MVVM will also behave differently. The model could be updated directly by an update by a backend server. Or for our code example, we could have a timer in the model adding pets every 10 seconds. For MVC, the Model will need a reference to the Controller in order to inform it and the Controller will have to update the views accordingly. On the other hand, using MVVM, when the model updates, the change is automatically published, and the Views will update itself.

When you follow the MVC pattern, you will most likely use imperative programming to do so. On the other hand, MVVM is largely associated with declarative programming. If all that sounds alien to you, just think of imperative as in “imperial”, where a single emperor (the controller) dictates everything. Whereas in declarative programming, the controller doesn’t instruct the view what to do, the view just reflects the current state of the program.

Personally, I prefer using MVVM especially since Apple has blessed us with SwiftUI. If you’ve ever had the chance to handle Massive-View-Controllers, I’m sure you feel the same way. Being able to program declaratively removes much of the complication behind trying to figure out which state the controller is currently in and generally makes debugging a much more “enjoyable” experience.

Conclusion

There are many more interesting ways to use MVVM and MVC and I’ve definitely not covered all of them. But I hope this article serves as a good introduction to these patterns and how to practically use them in your apps.

After you’ve seen the code, some parts of it may look like I rushed the article at the last minute to submit it for a school assignment because I only have 2 days left. But I assure you that’s not the case 🙃. In my next article, I’ll introduce a way to make our PetManager more flexible (because honestly it can only manage cats now). We’ll see how adding new classes like a Dog class will complicate things and how we can apply design principles to address these issues.

Happy Coding!

Live a life greater than yourself.