Discover the MVP 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 MVP 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:

This ViewController actually has quite a lot of responsibilities!

It must: fetch its data, format its data and then finally present 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 Presenter!

So let’s do it in 6 easy steps 🚀

Step 1️⃣, we create the Presenter:

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

Step 3️⃣, we abstract the ViewController behind a Protocol:

Step 4️⃣, we give the Presenter a reference to the ViewController:

Step 5️⃣, we extract the Business Logic to the Presenter:

Step 6️⃣, the ViewController can now rely on the Presenter to fetch, format and present the data 👌

And that’s it, we’ve successfully implemented the MVP Architecture! 🥳

Now our ViewController can focus on its core responsibilities of setting up the UI and reacting to user interaction, while the Presenter takes care of retrieving, formatting and presenting the data 👌

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

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    var presenter: Presenter?

    override func viewDidLoad() {
        super.viewDidLoad()

        presenter = Presenter(view: self)
    }

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

        presenter?.fetchData()
    }
}

extension ViewController: PresenterView {
    func display(newData: String?) {
        label.text = newData
    }
}

protocol PresenterView: AnyObject {
    func display(newData: String?)
}

class Presenter {
    let service = Service()

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

    weak var view: PresenterView?

    init(view: PresenterView) {
        self.view = view
    }

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

            DispatchQueue.main.async {
                self?.view?.display(newData: formatted)
            }
        }
    }
}
Previous
Previous

Discover some New Features of Swift 5.7

Next
Next

Discover the Coordinator Pattern