Battle of the iOS Architecture Patterns: View Interactor Presenter (VIP)

Radu Dan
Geek Culture
Published in
8 min readAug 27, 2021
Architecture Series — View Interactor Presenter (VIP)

Motivation

Before starting to develop an iOS app, we have to think about the structure of the project. We need to consider how we add those pieces of code together so they make sense later on — when we come back and revisit a part of the app — and how to form a known “language” with the other developers.

This is the final article of the “Architecture Patterns” series and we will going to see how we can implement VIP to the Football Gather application.

If you missed the other articles you can access them below or you can find the links at the end of this article.

  • Model View Controller (MVC) — link here
  • Model View ViewModel (MVVM) — link here
  • Model View Presenter (MVP) — link here
  • Model View Presenter with Coordinators (MVP-C) — link here
  • View Interactor Presenter Entity Router (VIPER) — link here

Are you impatient and just want to see the code? No worries! You have it available on GitHub.

Following the same approach as we did for the other posts, we will first say a few things about this pattern and why it’s useful. Then we will see the actual implementation.
Finally, we will show some figures about compilation and build times, check how easy was to write unit tests and state our conclusions.

Why an Architecture Pattern for Your iOS App?

The most important thing to consider is to have an app that can be maintainable. You know the view goes there, that this view controller should do X and not Y. And more important, others know that too.

Here are some advantages of choosing a good architecture pattern:

  • Easier to maintain
  • Easier to test the business logic
  • Develop a common language with the other teammates
  • Separate the responsibility of your entities
  • Fewer bugs

Defining the Requirements

Given an iOS application with six or seven screens, we are going to develop it using the most popular architecture patterns from the iOS world: MVC, MVVM, MVP, VIPER, VIP, and Coordinators.

The demo app is called Football Gather and is a simple way for friends to track the scores of their amateur football matches.

Main features

Ability to:

  • Add players in the app
  • Assign teams to the players
  • Edit players
  • Set a countdown timer for matches

Screen mockups

Screen mockups of “Football Gather”, the iOS app

Backend

The app is powered by a web app developed in the Vapor web framework. You can check out the app in my Vapor 3 initial article and the article about Migrating to Vapor 4.

Cleaning your code like a VIP

VIP is not an architecture pattern which is commonly used. It has been invented by Raymond Law and is intended to be Uncle’s Bob Clean Architecture version applied to iOS projects. More to find here: https://clean-swift.com/.

The main goal of VIP is to fix the massive view controller problem that we have with MVC. VIP also intends to provide a clean alternative to other architecture patterns problems. For example, VIPER has the Presenter at the centre of the app. VIP simplifies the flow by using an unidirectional way of control, becoming easier to invoke methods through layers.

VIP transforms your app control into VIP cycles, providing an unidirectional flow of control.

Example of scenario applying VIP:

  1. User taps on a button to fetch the list of players. We are in the ViewController.
  2. The IBAction calls a method from the Interactor.
  3. The Interactor transforms the request, performs some business logic (fetches the list of players from the server) and invokes the Presenter to transform the response in a presentable way for the user.
  4. The Presenter invokes the ViewController to display the players on the screen.

The architecture components are described below.

View/ViewController

Has two functions: sends requests to the Interactor and actions and displays the information coming from the Presenter.

Interactor

The “new” Presenter. This layer is the core of VIP architecture, doing stuff like network calls to fetch data, handle errors, compute entries.

Worker

In Football Gather we use “Services” for a name, but basically these are the same thing. A Worker takes some of the responsibility of Interactors and handles Network calls or database requests.

Presenter

Handles data coming from the Interactor and transforms them into a ViewModel suitable to be displayed in the View.

Router

Has the same role as in VIPER, it takes care of scene transitions.

Models

Similar with other patterns, the Model layer is used to encapsulate data.

Communication

The ViewController communicates with Router and Interactor.

Interactor sends the data to the Presenter. It can have send and receive events from Workers as well.

Presenter transforms the response incoming from the Interactor into a ViewModel and passes it to the View/ViewController.

Advantages

  • You no longer have the Massive View Controller problem you have in MVC.
  • Using MVVM incorrectly, you might end up having Massive View Models instead.
  • Solves the control problem from VIPER with the VIP cycle.
  • Using VIPER incorrectly, you can have Massive Presenters.
  • The authors say it follows the Clean Architecture principles.
  • In case you have complex business logic, it can go into a Worker component.
  • Very easy to unit test and use TDD.
  • Good modularity.
  • Easier to debug.

Disadvantages

  • Too many layers and gets boring after a while if you don’t use a code generator.
  • You write a lot of code even for simple actions.
  • Is not great for small apps.
  • Some of the components might be redundant based on your app use cases.
  • App startup will slightly increase.

VIP vs VIPER

  • In VIP, the Interactor is now the layer that interacts with the View Controller.
  • The ViewController holds a reference to the Router in VIP.
  • If used incorrectly, VIPER can grow massive Presenters.
  • VIP has an unidirectional flow of control.
  • Services are called Workers in VIP.

Applying to our code

Transforming the app from VIPER to VIP might not be as easy as you may think. We can start with transforming our Presenter into an Interactor. Next, we can extract the Router from the Presenter and integrate into the ViewController.

We keep the Module assembly logic that we did for VIPER.

Login scene

Moving on to our Scenes. Let’s start with the Login scene.

As you can see we no longer tell the Presenter that the view has been loaded. We now make a request to the Interactor to load the credentials.

The IBActions have been modified as below:

We start the loading view, construct the request to the Interactor containing the username, password contents of the text fields and the state of the UISwitch for remember the username.

Next, handling the viewDidLoad UI updates are made through LoginViewConfigurable protocol:

Finally, when the logic service call has been completed we call from the Presenter the following method:

The Interactor looks the same as the one from the VIPER architecture. It has the same dependencies:

The key thing here is that we now inject the Presenter through the initialiser and it is no longer a weak variable.

Loading credentials is presented below. We first take the incoming request from the ViewController. We create a response for the presenter and call the function presentCredentials(response: response).

The login and register methods are the same, the exception being the Network service (Worker).

The Presenter doesn’t hold references to the Router or Interactor. We just keep the dependency of the View, which has to be weak to complete the VIP cycle and not have retain cycles.

The Presenter has been greatly simplified, exposing two methods of the public API:

The Router layer remains the same.

We apply some minor updates to the Module assembly:

PlayerList scene

Next, we move to PlayerList scene.

The ViewController will be transformed in a similar way - the Presenter will be replaced by Interactor and we now hold a reference to the Router.

An interesting aspect in VIP is the fact we can have an array of view models inside the ViewController:

We no longer tell the Presenter that the View has been loaded. The ViewController will configure its UI elements in the initial state.

Similar to Login, the IBActions will construct a request and will call a method within the Interactor.

When the data will be fetched and ready to be displayable, the Presenter will call the method from the ViewController displayFetchedPlayers.

The data source of the table view can be seen below:

As you might notice, our cells don’t require a Presenter any more. We have everything needed (array of view models) in our view controller.

The Interactor is detailed below:

The Detail, Add, Confirm screens delegate are now moved from the Presenter to the Interactor:

Finally, the Presenter:

Testing our business logic

Switching from VIPER to VIP when unit testing the Gather business functionality is not as hard as it may seem.
Basically, the Interactor is the new Presenter.

We follow the same Mock approach, with boolean flags that are set to true whenever a function is called:

Here are some unit tests of the Interactor:

And the Presenter unit tests:

Key Metrics

Lines of code — Protocols

Lines of code — View Controllers and Views

Lines of code — Modules

Lines of code — Routers

Lines of code — Presenters

Lines of code — Interactors

Lines of code — Local Models

Unit Tests

Build Times

Tests were run on an 8-Core Intel Core i9, MacBook Pro, 2019. Xcode version: 12.5.1. macOS Big Sur.

Conclusion

We applied VIP to an application written in VIPER and the first thing we might notice is the Presenters are simplified and much cleaner. If we would be coming from an MVC app, the view controllers would be reduced considerably by separation of concerns

VIP simplifies the flow by using an unidirectional way of control, becoming easier to invoke methods through layers.

The average build times are similar with the ones from VIPER and MVP, around 10 seconds.
Having more unit tests, adds on top of the test execution time. However, we were a little faster than VIPER.

The Presenters have been greatly reduced with 514 lines of code compared to VIPER. But the main downside is that we gain the number of lines in the Interactors, overall being increased with 508 lines of code. Basically, what we took out from the Presenters we put in the Interactors.

Personally, I prefer VIPER. In VIP architecture there are things that I don’t like and from my point of view they are not following as much as they brag the Uncle’s Bob principles.

For example, why do we need to construct a Request object, even if there is nothing attached to it? I mean, we could not do that, but if you open up the repo of examples you can see plenty of empty requests objects.

There is a lot of boiler plate code.

Keeping an array of view models inside the ViewController creates complexity and can easily become out of sync with the Worker models.

Of course you can use your own variation of VIP that can mitigate these problems.

On a positive note, I like the concept of VIP cycles and how easy it is to use TDD. However, following a strict rule on the layers, each minor change can be hard to implement. It should be SOFTware, right?!

Useful Links

--

--