Intro to the VIPER design pattern (Swift 3)
VIPER is an acronym that represents an example of a design pattern that can be considered clean architecture. In essence, with clean architecture, you abstract your code into four layers: entities (models), use cases (business logic), controllers/gateways/presenters (handles UI logic), devices/UI/Web/DB/External interfaces (frameworks that could change).
VIPER stands for:
V — View (displays info to the user and detects user interaction)
I — Interactor (manipulates the entities/models by fetching data and storing data)
P — Presenter (without use of the UIKit, it contains the UI related business logic and prepares the data for presentation)
E — Entity (your model objects)
R — Router (aka wireframe, takes care of navigation in your module/application).
VIPER architecture allows for a clearer separation of concerns and separates the viewController from handling most of the responsibility in an app. Concerns are separated into modules for each use case (i.e. provide a map for the user). Each module has a clear layer of routing logic, presentation logic and business logic.
The View (the View Controller):
The view/view controller’s main purpose is to display info to the user and detect user interaction. The view/view controller intercepts user events and has ONE POINT OF CONTACT within the VIPER design pattern: the presenter. The view/view controller owns and sends user actions to the presenter. For example, a view/view controller will let a presenter know when it has started loading itself and when a user has tapped on a button.
The presenter receives user action information from the view/view controller and is responsible for the UI related (but not UIKit!) business logic data. The presenter prepares the data for presentation. The presenter has THREE POINTS OF CONTACT: the view/view controller, the interactor, and the router. The presenter owns the responsibility of fetching data from the interactor and preparing that data for presentation and passing it back to the view/view controller (so that it can be updated), of creating objects to be handed off to the router and determining if it needs more data from the interactor. I like to think of the presenter as the “mediator”.
The interactor has knowledge of our models, or entities, and fetches and stores data from a manager class (i.e. DataStore.swift). The presenter calls on the interactor for updated data and the interactor, in turn, provides it back. The interactor manipulates data (i.e. validates if a Map location has a valid name) and can call on a helper/manager class (LocationStore.swift) to create entities.
The entities are our data models (i.e. MapName, MapCoordinate, MapLocation). These entities are manipulated by the interactor. The interactor has full knowledge of the entities and their properties.
The Router/The Wireframe:
The router has ONE POINT OF CONTACT: the presenter. The router (aka the wireframe) owns a window and takes care of the navigation in a module. It creates the view controller and wires the presenter to serve as the output for the interactor and for the view controller to be the interface for the presenter. The presenter may know where to go, but the router knows how to get there.