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)
}
}
}