Adam Rush

@Adam9Rush

15 February, 2022

Introduction

A design pattern is used within programming to define a pattern of structuring your code. It’s used interchangeably with software architecture but not quite the same. Software architecture is more in detail and will illustrate how the software communicates, including data persistence.

Your design pattern is more specific about how you structure various components within your application. In this tutorial, we will explore MVVM (Model -> View -> View Model).

What is a Design Pattern

Design patterns describe a particular pattern that your engineering team will be following.

In iOS, we have various design patterns that are widely used:

  • MVVM
  • Viper
  • MVC
  • Coordinator Pattern
  • Delegate Pattern
  • Singleton
  • Factory

In this tutorial, you’re going to explore MVVM and nothing else, but do keep an eye on my website for more tutorials on the different patterns mentioned above. Learning about design patterns is essential, and you can guarantee this question will come up in your future interviews ;].

Before you start reading more, don’t panic too much about the words above, it will start making sense once we show some examples.

What is MVVM

The MVVM design pattern is undoubtedly one of the popular choices amongst iOS engineers. However, when Apple announced SwiftUI in 2019, it was the first time Apple mentioned a specific design pattern that worked very nicely with SwiftUI.

It sure means that Apple can envisage this design pattern working very well, and you’ll see for yourself in the examples below.

The MVVM design pattern is broken down into three sections:

  • Model
  • View
  • ViewModel

Model

The model is the data model, and this is typically your struct object that is mapping the raw data from your server or similar.

struct Bank {
    let paymentType: String
    let balance: Float
}

Your example above is mapping the Bank object from an API call to get the paymentType and the balance.

Typically, you’ll have many models, and it’s the rich business data you’re retrieving.

ViewModel

The ViewModel is usually an object initialised with the raw model defined above.

class BankViewModel {
    
    let bank: Bank
    
    init(with bank: Bank) {
        self.bank = bank
    }
    
    func bankBalance() -> String {
        return "£\(bank.balance)"
    }
}

Your ViewModel is designed to be a question and answer for your ViewController or similar. If you think about the questions your ViewController is likely to have:

  • What is my balance?
  • What payment methods can I use?
  • Who is the logged in user?

These are real-world questions that you ViewController or View is likely going to need answers so you can provide this data in the UI.

The ViewModel is acting as a facade between your data model and your View.

In my opinion, the ViewModel shouldn’t have any reference to anything inside UIKit, it should simply provide answers so the View can render the UI.

View

Your View is typically your UI in the application, something that is visible on the screen.

class BankView: UIView {
    var bankViewModel: BankViewModel {
        didSet {
            updateUI()
        }
    }
    let bankLabel: UILabel
    
    init(with viewModel: BankViewModel) {
        self.bankViewModel = viewModel
        self.bankLabel = UILabel()
        
        super.init(frame: .zero)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func updateUI() {
        bankLabel.text = bankViewModel.bankBalance()
    }
}

You have created a very simple UIView that represents a BankView. This is super simple, but you get the idea.

Your ViewController would typically look like this:

var bankViewModel: BankViewModel = BankViewModel(with: Bank(paymentType: "", balance: 10))

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
        
    let bankView = BankView(with: bankViewModel)
    view.addSubview(bankView)
    }
}

You can, of course, create the ViewModel when you get the Bank data from an API call, but this is just an example. You might have a network layer or similar that will create these Models -> ViewModels.

Documenting Your Definitions

The MVVM design pattern in visual format.

You might already be familiar with the above, and that’s awesome; you might also be brand new to the industry and learning best practices. My most extensive advice is to open a brand new Xcode project and create the above examples into a working project.

The most significant benefit to MVVM is that you’re not exposing all the rich business data directly to your Views and creating isolated access, which is often great, especially for the more significant projects.

It would help if you also documented your MVVM responsibilities. Of course, many engineers will create different interpretations of design patterns, which is perfectly fine; it’s not a one-fits-all approach, and some engineering teams will slightly vary the above implementation.

However, my biggest advice is to make sure you document the responsibilities for each one. For example, you could create an “MVVM Rulebook” and define what the responsibility is for each Model -> View -> ViewModel. Then, you could create a similar tutorial like this but for your engineering team.

That way, onboarding new engineers will be simple and ensure you have a consistent approach across your codebase.

What Next?

It would be best if you started playing with the above example, and why not explore how it works nicely with SwiftUI. The more you practice doing this, the more confident you will become.

I can’t wait to see what you do with MVVM next :]

Sponsor

Subscribe for curated Swift content for free

- weekly delivered.