Discover the MVVM Architecture


You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿


The MVVM Architecture can feel a bit mysterious when you’ve never used it 😶‍🌫️

But I swear it’s really simple to understand! 😌

In just a few paragraphs we’ll go over everything you need to understand how this architecture works!

Let’s start with this ViewController:

If you think about it, this ViewController actually has a lot of responsibilities!

It must: fetch its data, format its data and then finally display its data 💪

With so many responsibilities, this ViewController will become harder and harder to maintain as our app will grow in complexity 😰

That’s why it makes sense to extract some of these responsibilities to another object called a ViewModel!

So let’s do it in 6 easy steps 🚀

Step 1️⃣, we create the ViewModel:

Step 2️⃣, we extract the Service and the Formatter to the ViewModel:

Step 3️⃣, we add a callback to update the UI whenever the data gets updated:

Step 4️⃣, we move the logic to fetch and format the data to the ViewModel:

Step 5️⃣, we provide the ViewController with an instance of the ViewModel:

Step 6️⃣, the ViewController can now rely on the ViewModel to fetch and format the data:

And that’s it, we’ve successfully implemented a simple version of the MVVM Architecture 🥳

Here’s the code if you want to experiment with it!

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    let viewModel = ViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()

        viewModel.updateUI = { [weak self] newData in
            self?.label.text = newData
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        viewModel.fetchData()
    }
}

class ViewModel {
    let service = Service()

    let formatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .spellOut
        return formatter
    }()

    var updateUI: ((_ newDataToDisplay: String?) -> Void)?

    func fetchData() {
        service.fetchNumber { [weak self] newNumber in
            let formatted = self?.formatter.string(for: newNumber)

            self?.updateUI?(formatted)
        }
    }
}
Previous
Previous

Discover Dependency Injection