Lightweight MVP architecture in iOS

Ruslan Fedorovich
OmiSoft
Published in
5 min readJul 26, 2019

Hi there!

This article is going to provide you with some theory about the MVP pattern, as well as to inform you about one of the ways to implement it in your iOS application through the illustrative example.

I use this approach on medium-sized projects because there is a clearer distribution of responsibilities, but at the same time, there is no crockitude as, for example, in VIPER.

Let’s get started!

Briefly about MVP

Image 1. The General MVP Scheme. Credit: https://www.techyourchance.com/

MVP stands for Model-View-Presenter. It is based on the distribution of responsibilities among the three modules:

Model contains data

View is responsible for displaying data

Presenter, an intermediary between the two modules mentioned above, is responsible for the screen logic

To get to the main idea, let’s compare it with, one can say, the standard pattern in iOS — MVC (Model-View-Controller).

The key problem of the MVC pattern in Swift applications lies in the fact that basically for almost all the actions occurred in the application the same file, namely, ViewController, is responsible. Processing user actions, requesting data from the network and all the logic are done by this module. That’s not a problem for very small applications. However, in other cases, when an app has a great number of functions, the wealth of code makes out of ViewController some crockitude and unreadable dump (so-called Massive-View-Controller).

MVP Example

Let’s look at the way how to implement the MVP (Passive View) pattern using a simple application as an example: https://github.com/OmiSoftNet/MVP-Template-iOS

Image 2. The Test Application Interface: (a) a list of newspapers (b) a summary about the newspaper

This application shows a list of newspapers ever published in the United States and after clicking on a newspaper from the list, it shows brief information about it.

The data source is a free API from Chronicling America website.

Respectively, it consists of two screens, namely, a list of newspapers (Image 2a) and a screen with details about the newspaper (Image 2b).

Let’s take a look at the features of the MVP pattern implementation in the application. Each scene/screen consists of three components:

ViewController, a class responsible for displaying data, performs the role of View in MVP

Presenter is a class implementing the interaction between the Model and View Controller

MvpView is a ViewController’s interface (protocol), a delegate through which Presenter communicates with ViewController

Basic Classes for MVP

You will surely notice that each of these screen components is inherited from superclasses.

So, to avoid any confusion in the future, let’s briefly learn them.

These superclasses contain the code of MVP components’ interaction. It is included there to avoid repeating this code in each of the screens.

Most of the code in them relates to routing, which will not be discussed in the current article.

However, it is necessary to pay attention to the fact that:

  1. The generic variable “presenter” in BaseVC has the type of the Presenter that is used with this ViewController’s.
  1. MvpPresenter contains the variable “mvpView” through which Presenter “gives commands” to ViewController. Type V is a protocol implemented by ViewController.

This module contains three files:

  1. ViewController
class NewspapersListVC: BaseVC<NewspapersListPresenter>

2. Presenter

class NewspapersListPresenter: MvpPresenter<NewspapersMvpView>

3. Protocol

protocol NewspapersMvpView: MvpView

Below we see ViewController and Presenter of this screen, respectively, which will be considered in conjunction:

Unlike ViewController in MVC, our ViewController is severely limited in its functions.

As mentioned at the beginning of the article, in the MVP pattern, our ViewController plays the role of the letter V in MVP. It means that it is responsible only for managing the objects of the user interface and notifying Presenter. It should not have access to services and business logic. Ideally, it is simply a “tool” of Presenter and does not make any independent decisions.

Let’s take a look at viewDidLoad method (a method that is called when the screen starts). In the body of the function, ViewController notifies (the call to the doOnStart method) that it has been loaded and then “waits for instructions from it”.

It is evident that in this case it does not make any independent decisions, but only notifies Presenter.

Looking at the doOnStart body in Presenter of this screen, we see the line:

fetchNewspapers()

It calls the function that accesses the service responsible for working with API, to provide it with a list of newspapers and models.

After the newspapers have been received, Presenter “orders” the View Controller to be updated to display a list of these newspapers.

The “orders” i. e. the methods that Presenter can call are written in the protocol:

protocol NewspapersMvpView: MvpView {
func updateList()
}

and implemented in the ViewController extension:

extension NewspapersListVC: NewspapersMvpView {
func updateList() {
tableView.reloadData()
}
}

And now we can finally look at the full picture, particularly, the class diagram for this screen:

Image 3. Class Diagram of Newspapers List Screen

You can find the whole code here: https://github.com/OmiSoftNet/MVP-Template-iOS.

Summary

As a result, it is clear that each component performs its role: ViewController updates the interface objects and notifies Presenter about any events. Presenter processes updates from the view, receives data from the model, and notifies the interface back (in our example, after receiving a request from the view, our Presenter received the list of newspapers and gave it to the view for updating the interface). And the Model is responsible for the business logic and data provision.

If this application was developed using the classic MVC implementation in iOS, the role of Presenter and the view would go to one class, ViewController, and in addition to managing the interface objects, it would have to receive and process the model’s data. On the other hand, this architecture is more compact than, for example, VIPER, and therefore it is well suited for small projects.

In the end, I’d like to briefly recall the basic rules of the MVP pattern:

  1. Presenter does not have access to the user interface objects, this role is assigned to ViewController.
  2. ViewController should not make independent decisions, but only notify Presenter about the events.
  3. ViewController, in the ideal case, “communicates” only with Presenter, all other parts of the application are not accessible to it.

Tap the 👏 button if you found this article useful!

About the Author
Ruslan is a pixel-perfect maniac of iOS Team at OmiSoft.

Need an iOS mobile app with clean & maintainable code? Click here to get an estimate! Or find us on Facebook and Twitter.

--

--