iOS VIPER: Presenter x Interactor responsabilities in different situations

Image from https://unsplash.com/wallpapers/nature/forest

I think one of the most relevant questions regarding VIPER is about the separation of tasks between its layers. Its's clear enough, according to our previous article that View is only responsible of displaying our UI with proper content and build hierarchy; Router takes care of all context changes(popups, modals and change of screen); Entity is a data model describing some entity from our business(usually a struct or enum).

However, a lot of people come to me asking things like:

For short, several developers don't know a 100% how to separate Presenter and Interactor and what exactly are use cases. That's the purpose of this article, to answer these questions and provide a more accurate definition for each of these layers. I will provide some examples. But keep in mind that I am not the source of truth and different people may disagree with me by having a different point of View(if you think different, please, paste your point of view as a comment). What I am about to show you is just the way which I would structure my own project. Hope you like it!

What are use cases?

For many people this shall be an obvious question, use cases are like a sequence of interactions in the application that receive an input and this sequence also produces an output to be consumed by the next scenario. What folks usually get lost in is about if it's related to UI or not.

Let's imagine you have a sign up screen where some personal information is requested: you need to provide your name, your email, a password and a password confirmation. Simple as that. As normal, this scene has some validation rules before submitting the inputs to back-end:

These validation rules should be handled by Presenter or Interactor? That's the big question. Let me answer that in my way:

There are three questions you should ask yourself about this scenario:

If you answered YES to any of these questions an Interactor call is certainly needed.

A use case is much more than presentation, it's business logic. I have a more precise way of defining that:

A use case is any interaction with the system that cause changes to our Entity-Relation diagram, being it related to the whole ecosystem or just a scene scope.

For this scenario where we are only validating when when a button should appear, there is no business core being changed, just presentation, so everything can be executed inside Presenter .

Feature flags and project configuration

Image from https://br.pinterest.com/pin/230809549630721706/

If you still don't understand the purpose of feature flags, I strongly recommend you to read this article. Feature flags dictate a behavior in your application that may be controlled by an outsider or by its own developer when testing some specific scenario in an environment. People(me included) discuss a lot about if that belongs to our presentation logic or if fetching a configuration is part of some use case. The answer is: it's just presentation logic.

There was a time in a project that I worked years ago when I faced a problem that I needed to fetch an environment variable that was different depending on the target I was working. This project had three white labels(three apps, three design systems, three configurations, same project) and each one had a different value for this variable. This variable was just a string describing the section order for a help center screen. A configuration piece of data is related to the environment you are working, that's how that application works and there is nothing that can change it(at least in this scenario). So I fetched that from our FeatureFlagManager class from Presenter itself and then proceeded with the logic. The code was something like:

People may think it should belong to Interactor and I respect them, but regarding my concept and answering those three questions:

We answered NO to all three questions, so it should be applied to Presenter , not Interactor .

Parsing environment data

In this same example I described above, I needed to take this sectionOrder string and parse that in order to translate to a more readable array of section enum cases with associated values to fill our screen. Each section corresponded to a UITableViewCell and their content was an associated value to be filled. These were the sections:

My enums were something like:

There was a logic restricted to this screen regarding how that string from the configuration file would be parsed into a list of section enum cases. So, discussing with the iOS team, we decided to place that method within the Interactor and fetch that from the Presenter . The enum case array would dictate what are the cells our Presenter would created according to each case and value:

So our Presenter is responsible for fetching the given string for sections order, then it's parsed by the Interactor to describe better what are the sections. When the output is received, Presenter creates cells according to that and passes to our View .

Static data

Sometimes our screen doesn't even have any logic nor interaction with the user. Screens like error, success, coachmarks, tutorials and warnings where the only option for the user is confirming or maybe closing.

These cases rely on static texts or numbers to fill our UI. For these cases I wouldn't even recommend an Interactor layer since we are not triggering any use case at all. However, some literatures recommend creating an empty Interactor class without any method. In my personal opinion, keeping an empty Interactor would only increase unnecessary complexity and can be discarded since it's optional.

For that, you may keep all the static texts in the Presenter:

Since in this case there is no interaction that could change our UI, a ScenePresenterOutput protocol is not required.

Analytics

All the mobile and web applications retain analytics events being triggered according to user interactions. If you don't know what are analytics, it's basically a way to log each user interaction event or variable output from an external source, like a presented screen, a succeeded or failed API call, a clicked button or a scrollable content that achieved the end of screen, but it's a topic for another article. What we are discussing here is about where analytics events should be triggered: Presenter or Interactor? The answer is: Presenter.

Not every time we shall have an Interactor as discussed before and not always a user interaction will trigger an use case. With that in mind, all the UI events shall be logged in the Presenter itself. The only exception for that is when we are logging an API result, that may be logged by the Interactor since there is the place where we directly receive results.

Where should I first inject data from previous scene?

You may be thinking about where should you save the input data. This data may be used to directly present some content, maybe for fetching remote data from an API or it might be used to imply in an use case, user interaction output. The answer is: Both layers work.

For example, if you are just injecting some name that may be displayed as a static title, Presenter is the right place:

But if this input data is about to be related to an use case, like to be part of an endpoint, there is nothing wrong to inject directly in our Interactor :

Conclusion

This article brought you a better understanding about the different meanings Presenter and Interactor have in a VIPER architecture and when it's time to rely on each one. Basically you need to ask yourself if the operation you need operates with data entities, if it calls some external service or if it has some screen business logic. If at least one of these cases occur you need an Interactor. We also showed some of the most common examples of operations inside a scene and how to handle each one. I hope you are now more secure about building a new VIPER scene and ready to apply these skills in your personal projects ;)

--

--

iOS developer- WWDC19 scholarship winner- Blockchain enthusiast

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store