-
Notifications
You must be signed in to change notification settings - Fork 9
VIPER
iOS is still a very young technology and as you may have found out an MVC architecture is anything but useful for long running applications. The fuboTV iOS application is adopting the VIPER architecture throughout.
VIPER is a 6 tier architecture that abstracts module tasks into each tier such that everything has a single responsibility. Its conforms to SOLID design principles and is an implementation of Clean Architecture concepts.
Main Goals Of VIPER:
- Make code easy to iterate on
- Make projects collaboration-friendly
- Create reusable modules with separated concerns
- Make code easy to test
A very simplistic representation would be:
- Wireframe (Router) - instantiation and navigation
- Presenter - business logic
- Interactor - data logic
- View - user interface
- Service - retrieves entities
- Entity - data object

Most connections are two way and each direction is abstracted into an interface. For example:
- Wireframe talks to the Presenter through the WireframeToPresenterInterface
- Presenter talks to the Wireframe through the PresenterToWireframeInterface
The abstracted interfaces provide us with a way to easily conform to the interface (Goal 2 & 3). This lets us easily replace objects by creating new objects that only need to implement the interfaces (Goal 1 and 3). This also lets us create mock objects that can easily be injected for testing (Goal 4).
VIPER is not the end all of architectures. It solves many problems that arise from MVC, but sometimes the technology of our IDE's doesn't mix well (ex: storyboards and segues). If you see a way to improve VIPER, please be vocal, we want it to improve!
The wireframe is responsible for instantiation and navigation. It is the interface into the VIPER stack. When creating a VIPER stack, you instantiation the wireframe and it instantiates all the other layers and connects them properly. A wireframe constructor could look like this:
lazy var moduleInteractor = Interactor()
lazy var modulePresenter = Presenter()
lazy var moduleView = View()
init() {
super.init()
let i = moduleInteractor
let p = modulePresenter
let v = moduleView
i.presenter = p
p.interactor = i
p.view = v
p.wireframe = self
v.presenter = p
}The wireframe maintains strong references to module layers so they do not get deallocated. It initializes all of them, and connects each one to the other, correctly.
With navigation, its specifically navigation to the stack or away from the stack. Lets say you want to display a login stack from the home stack of the application. The home wireframe would have been told to present the login stack, and it will call the login's wireframe (which implements the module's interface) presentation method. Something like this:
//HomeWireframe.swift
lazy loginModule: Login = LoginWireframe()
func presentLogin() {
loginModule.present(onViewController: moduleView)
}
//LoginWireframe.swift
func present(onViewController viewController: UIViewController) {
viewController.present(moduleView, animated: true)
}There are several blogs and internet sites that explain VIPER and its target benefits with a different perspective. Here are a few: