MVP vs. MVVM in iOS Development

Ahmed Ragab Issa
12 min readJan 2, 2020

--

Let’s discuss those architectural patterns and structure our knowledge.

Photo by John Schnobrich on Unsplash

You may feel bad while developing using MVC in iOS and want to switch to another architecture like MVP or MVVM, but not sure if it worth it?

Let’s discuss each of them together and find the answer. :D

You are about to structure your knowledge about the MVP and MVVM architectural patterns in iOS development. We will figure out the strength and weakness of each of them.

This article for you if you asking yourself questions like:

What are the responsibilities of the Model / View / Controller / Presenter / View Model Should own?

Who supposed to own a networking request: the Model or the Controller?

How to reuse View with it’s View Model or Presenter on MVVM or MVP as a subview to another view? and what if those are multiple reused views on the same super view?

Some traits of good architecture are:

  • A balanced distribution of the responsibilities among the entities and respect the Single responsibility principle from the SOLID principles.
  • Testability is the magic of saving developers from finding issues live, which might happen when an app is on a user’s device.
  • Maintainability is how the app responds to new changes, it should welcome requirement changes.
  • Scalability is how easy to scale the app by adding new features.
  • Reusability is to what limits the entities are reusable, we should try to increase the number of reusable components as possible.
  • Developers Knowledge: it’s important to consider the level of the developers who will work on the project or support it. If they are juniors with limited skills we should try to make it easy to use as possible.

For better understanding, we will first quickly explore the MVC architectural pattern iOS version.

MVC iOS version

“Model-View-Controller”

Apple’s MVC

The MVC iOS version is a different flavor of the traditional MVC, as in the traditional MVC the view and the model know each other and also the controller is separate from the view.

  • Model: responsible for the domain data or a data access layer which manipulates the data, think of ‘Movie’ or ‘MovieDataProvider’ classes.
  • View: responsible for the presentation layer (GUI), for the iOS environment, think of everything starting with ‘UI’ prefix. Like a UITextField
  • Controller: the glue or the mediator between the Model and the View, responsible for altering the Model by reacting to the user’s actions performed on the View and updating the View with changes from the Model.

You might have noticed that a lot of code seems to “naturally” go into view controllers. Because view controllers in iOS carry many responsibilities and are closely related to the app screens, a lot of code ends up being written in them because it’s just easier and faster that way. In the long term, though, all of this code piles up and becomes hard to read, modify, reuse and test. This happens so often that the joke is that MVC is short for “massive view controller

Let’s discuss the MVC in the traits of good architecture we defined at the beginning of the article:

  • A balanced distribution: the View and Model are well separated, but the View and the Controller are tightly coupled, which makes the Controller violate the single responsibility principle.
  • Testability: due to the bad distribution you’ll probably only test the Model, to test the ViewController you will need to simulate the view controller life-cycle methods call (viewDidLoad, viewWillAppear, …) which might cause loading all views, and this is not good for unit testing.
  • Maintainability: it’s hard to maintain as the controller gain may responsibilities while the app growing.
  • Scalability: due to the bad distribution it can’t scale up easily.
  • Reusability: due to the bad distribution you’ll probably only reuse the Model.
  • Developers Knowledge: it’s the Appel’s default architecture when creating a new app. So, all the developers are familiar with it, thus, it’s easily maintained even by the unexperienced developers.

Note: we didn’t go through the traditional MVC as it doesn’t make much sense due to the architectural problem — all three entities are tightly coupled, each entity knows about the other two. This dramatically reduces the reusability of each of them — that is not what you want to have in your application. For this reason, we skipped it.

MVP

“Model-View-Presenter”

MVP

It looks like the MVC Apple’s version, but it’s not similar, because if you recall, there, the View is tightly coupled with the Controller in the MVC, while the MVP’s mediator, Presenter, has nothing to do with the life cycle of the view controller, and the View can be mocked easily, so there is no layout code in the Presenter at all, but it is responsible for updating the View with data and state.

  • Model: exactly as Apple’s MVC Model.
  • View: exactly as Apple’s MVC View.
  • Presenter: same as the controller on the traditional MVC as it is the mediator between the Model and the View, responsible for altering the Model by reacting to the user’s actions performed on the View and updating the View with changes from the Model.

Note that the Model and the View are the same on MVP and Apple’s MVC version, but different on the traditional MVC as on the traditional MVC the View and the Model can interact with each other,

Note that the MVP View = UIViewController

The UIViewController subclasses are the Views which is separate from the Presenters, which makes the presenters testable, On the other hand, it affects the development speed as you have to implement data and event binding between the Views and the Presenters.

Example:

Let’s have a very simple example to understand each part of the MVP well, Our Weather App target is to have a TextField that receive a city name, and Query Button to get the weather temperature for this city.

Here is the UI output of our example:

MVP Example — initial state output
MVP Example — final state output

Note: we have no focus on building awesome UI, we just focus on the architecture.

[code 1] Weather Model and WeatherProvider class

1- Our Model to hold the city name and temperature, the model here is a dump.

2- In our example, we don’t need to know from where to get the weather for a city, So, we implemented a dump WeatherProvider class that contains a getWeather function that takes the city name as input and returns a weather object with a random temperature between -30 & 60.

[code 2] MVP Implementation

1- WeatherViewProtocol is for referencing the view on the presenter without depending on the view controller, which makes the presenter testable and reusable with other views. The view that needs this presenter should conform to that protocol, as our WeatherViewController. This also enables us to mock the View easily to test the presenter.

2- WeatherPresenterProtocol do the same as WeatherViewProtocol do but for the presenter.

Those protocols helped us to satisfy the Dependency Inversion Principle (DIP) from the SOLID Principles to depend on abstraction not implementation.

3- WeatherPresenter is our Presenter which implements the WeatherPresenterProtocol to expose the function showCurrentWeather to the View, to enable the View to pass the action when the user clicks on the Query button and pass the city the user typed. which gets the weather and updates the View with the result using the setWeather function from the View.

4- WeatherViewController is our View which implements the WeatherViewProtocol to expose the function setWeather to the Presenter, to enable the Presenter to update the View with the result when needed.

5- This line is to initialize the Presenter for the View, this is not the best practice but it’s good enough for our example. For better solution try to add a Router Layer to assemble the Model-View-Presenter components and handle the presentation between the Views.

note that the point number 5 also exist on MVVM. but with the View Model.

Note that the MVP has other flavors, you can totally implement it without using any protocols by taking reference from the View itself on the Presenter and the same with the Presenter reference on the View. But, this implementation make the Presenter not testable and not reusable, and make the View not reusable. you can try it yourself and figure out it’s problems in reuse and test.

Let’s discuss the MVP in the traits of good architecture we defined at the beginning of the article:

  • A balanced distribution: most of the responsibilities divided between the Presenter and the Model, with the pretty dumb View.
  • Testability: it’s testable, we can test most of the business logic because here the view is dumb.
  • Maintainability: it’s maintainable as the presenter separates the presentation and business logic from the view, which enables us to maintain each of them separate from the other.
  • Scalability: it can be scaled up safely due to the responsibilities distribution.
  • Reusability: because the presenter depends on the view you’ll probably only reuse the Model.
  • Developers Knowledge: the idea of the MVP is very clear and popular. So, even the unexperienced developers can understand and maintain the project.

Note that the MVP provides us an acceptable level of testability, but requires a lot of code to be implemented.

MVVM

“Model-View-ViewModel”

MVVM

MVVM is pretty similar to the MVP, The View and the Model are already the same and familiar to us, but instead of the Presenter, we have a View Model as the mediator. Also, the MVVM treats the view controller as the View. And there is no tightly coupling between the View and the Model.

  • Model: exactly as MVP.
  • View: similar to the MVP View with one more responsibility to update its state from the View Model by setting up bindings.
  • View Model: it is basically UIKit independent representation of your View and its state at any time. The View Model invokes changes in the Model and updates itself with the updated Model, and since we have a binding between the View and the View Model, the View is updated accordingly.

Note that the View Models in iOS have many different implementation flavors you can find some of them in the following article.

Binding

Binding refers to the flow of information between the views and the view models. In the iOS toolbox, we have no appropriate binding paradigm. Yes, we have KVO and Notifications, but they aren’t as convenient as bindings.

So, we have 3 options:

Note: to use MVVM with its full power you have to use one of the reactive programming frameworks, but you have to know that when it comes to reactive programming the debugging will be more harder and take much time to fix bugs because of the binding.

Think twice before choosing the binding method you will use in real projects.

Binding Types

If we have a text field called nameTextField and variable called name, let’s explain the binding ways on them:

  • One-Way binding: is the way of binding when to bind one of them to the other one. For example, we use it if we only need the variable name always reflect the text value of the nameTextField once it’s text changed instantly.
  • Two-Way binding: is the way of binding when to bind both of them to each other. Once one of them is changed the other one changed instantly.

Example:

Let’s Implement the same example we implemented for the MVP. but with a little bit of change to highlight the benefits from the binding.

The user will type the city name and click on the Start Button, and the result will update every 10 seconds.

MVVM Example — initial state output
MVVM Example — sample of the final state output

As you know the Model is the same on both the MVP & MVVM. So, we will reuse the same code on the code block number [code 1] that discussed before, if you forgot it go up and read it again.

Let's reimplement the core part of the sample using MVVM:

1- WeatherViewModel is our View Model which is a representation of the View state at any time which get updated temperature for the queryCity every 10 seconds and update the Model and update itself according to the Model updates, and due to the binding between the View and the View Model the View is instantly updated.

2- The bindWeather is a closure to bind the weather result from the View Model to the View.

3- The queryCity is variable to bind the cityTextField updated text to it once changed.

4- Once the Model changed we need to update the View by calling the view binding closure which is in our case “bindWeather”.

5- The refreshTimer is a timer to update the weather model every 10 seconds with the updated temperature for the variable queryCity.

6- The function refreshWeather is the function that the refreshTimer calls every 10 seconds to update the temperature.

7- The WeatherViewControllerMVVM is our View which will consume our WeatherViewModel and bind itself to it.

8- The View passes the binding closure to the viewModel once it’s initialized. which updates the weatherResultLabel with the result.

9- Adding target to the cityTextField for the event of editingChanged to bind it’s updated value to the variable queryCity which exist on the viewModel.

Note that from points 5, 8 & 9: every 10 seconds the result will be updated for the last city the user typed on the text field even if the user updated it many times after clicking on the start button, which is really amazing :D

10- This line is to initialize the View Model for the View. Also, it’s better to use a Router layer as mentioned before on the MVP.

Using a Router may be useless and add more complexity to the project. So, before using it read about it and you should have a reason to use it.

Let’s discuss the MVVM in the traits of good architecture we defined at the beginning of the article:

  • A balanced distribution: it is balanced in the responsibilities distribution like the MVP, but the MVVM’s View has one more responsibility because it updates its state from the View Model by setting up bindings.
  • Testability: the View Model is fully testable as it knows nothing about the View.
  • Maintainability: it’s more maintainable than the MVP as the View Model knows nothing about the View, which enables us to maintain each of them separate from the other.
  • Scalability: it can be scaled up safely due to the responsibilities distribution.
  • Reusability: the View Model knows nothing about the View. So, we can reuse it easily and bind it with another view. Also, we can reuse the View and the Model.
  • Developers Knowledge: MVVM has different binding flavors as mentioned before in the article. So, Apps implemented using MVVM may require experienced developers to maintain. Also, the debugging of reactive programming is tricky and may take a lot of time to find and fix the bugs.

MVP vs. MVVM

Let's conclude the main differences between them which should be considered to select one of them for a specific project.

  • The View Model represent the View current state exactly, while the Presenter not.
  • The MVVM requires binding to be implemented and to have its full power it should be using reactive programming. while the MVP not.
  • Reactive Programming is hard to debug to find the bug and also to solve it without violating the project architecture.
  • The Presenter depends on the View by having reference from it. Which should be mocked to be testable. And to mock it you need this reference to be from Protocol to depend on abstraction. but the View Model doesn't depend on the View at all.
  • The MVP is more common and the developers familiar with more than the MVVM. the core of this point is the binding way you use, which may be new to MVVM familiar developers too.

Architectures are not here to solve our problems, they help us to do so. ‘There is no silver bullet’ and each design pattern architecture has its pros and cons. And each one of them is destined to tackle a certain situation, so use them wisely.

Reuse Tips and Tricks:

  • Implement the MVP with the protocol flavor to enable the reuse.
  • If you need to reuse multiple View Models on one new View, wrap them in another new View Model, as each View should have only one View Model. And this new View Model implements the reuse logic.
  • If you need to reuse multiple Presenters on one new View, implement the presenter protocol of this new view to inherit all the reused presenters protocols, as each View should have only one Presenter.

Thank you. If you liked this article, please clap so other people can read it too.

Any feedback is highly appreciated.

--

--