The MVC Architecture is generally used in developing iOS applications.
However the “ViewController” approach widely used is the most evil part that messes up Views and Controllers: Developer writes both view animation and business logic in the UIViewController, hence introducing a MEGA-ViewController.
In this passage, we will share our experience on how VIPER saves our lives from this monster in one of our projects.
VIPER is not a framework but an approach to iOS application architecture, which stands for:
The “MVC” monster
Typical Model objects are simple, they are just NSManagedObject.
View and Controller are wrapped in a single UIViewController class. The UIViewController class constraints the fundamental view management of the iOS app. As the name convention suggests, view controllers often handle both business logics and logics for responding to user interactions.
For smaller scale applications (with less model and UI interactions), this should not be a nightmare.
But when we were building a slightly more complex application that includes several models and live UI updates, this leads to the most evil situation: resulting of a MEGA-ViewController. This makes the typical view controllers massive and difficult to test.
The resulting ViewController actually violates the original MVC design that views are not supposed to have access to models.
The view consists of views and view controllers. It is responsible to receive user interactions and pass them to presenters for decision making. To keep the view simple, it shouldn’t contain any view logics. This is where to define how the view looks like, and nothing beyond this.
The presenter defines the view logics, e.g. when to show a warning message or highlight a button. It is responsible to prepare content for the view to display. Whenever data is required, the presenter requests data from interactors (but not directly from the model).
The interactor mainly contains business logic, e.g. logging in the user / processing a purchase / sending a friend request. It should be independent of the UI. It only handles requests from the presenter and prepare corresponding data regardless of how the view looks like.
Entities are the model objects manipulated by an Interactor and only by the Interactor. It is simply an NSManagedObject. It is model orientated and therefore should not contain any business logic.
is not supposed to be placed inside an Entity.
Wireframe defines the routes from one screen to another. In VIPER, the responsibility for Routing is shared between the presenter and the wireframe.
When the presenter receives user interactions and decided to navigate to another screen, it will use the wireframe to perform the desired navigation (to which screen and how to navigate). The wireframe can also contain transition animations.
What does VIPER help us achieve?
If MVC is a mega-monster that troubles you, VIPER is a little-monster-collection that aids you in building iOS apps – in a more delightful and controllable way.
By implementing the VIPER architecture, we successfully break down complex logical structures into layers of well-defined responsibilities. And yes, we did this in the early architecture design phase.
Now, we can finally say “good-bye” to the Mega-ViewControllers.
By separating responsibilities, it also enhances isolating dependencies. This makes testing and debugging much easier. Since the physical files are becoming smaller and putting more focus on their corresponding responsibilities , it facilitates team collaboration.
To help illustrate how we work with VIPER, in this example, we would like to show how we define components for a signup page.
At the first time the app launch, we have a SignupViewController as the rootViewController of AppDelegate.
@interface LoginPresenter - (void)loginButtonTapped:(NSString *)email password:(NSString *)password; @end
@protocol LoginPresenterProtocol - (void)showErrorMessage:(NSString *)message; @end
@protocol LoginInteractorProtocol <NSObject> - (void)requestSuccess; - (void)requestFailed:(NSString *)errorMessage; @end
@interface LoginInteractor : NSObject <ETRequestManagerProtocol> - (id)init:(NSString *)email password:(NSString *)password delegate:(id<LoginInteractorProtocol>)delegate; - (void)startRequest; @end
@interface WireFrame : NSObject - (void)navigateToMainScreen; @end
To get started easier, we’ve prepared a list of notes to make sure everything follows the VIPER’s design principle. We hope this will be useful to you also as we find it to be.
Views and view controllers receive user interactions and pass them to presenters for decision making
Presenters contain the view logics and prepare content for display and reacting to user inputs
Presenters should not know about the existence of all UIViews
Interactors contain business logics and they should be independent of UI
Entities are model objects manipulated by Interactors
Wireframe is the only place to define screen navigations and their transition animations
We hope you enjoyed reading this post. If you also find the “Mega-ViewController monster” a nightmare for your iOS Application, VIPER might be one of the solutions.
As said in the very beginning, VIPER is an proposed architecture that components should be defined according to your own usecase. And we find this structure quite suitable for most Startup usecases 🙂
We will continue to share our experience in exploring interesting yet useful engineering technologies and tools in the future.
If you have any thoughts or comments, please do not hesitate to comment below.
VIPER on objc.io
Blog by Brigade Engineering sharing about VIPER
If you find this post interesting, subscribe to our newsletter to get notified about our future posts!