Skip to content
Ryan Bush edited this page Apr 14, 2017 · 11 revisions

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.

What VIPER Is

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

A VIPER Stack

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).

What VIPER Is NOT

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!

VIPER Layers Explained

Wireframe

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)
}

Some Alternative Resources

There are several blogs and internet sites that explain VIPER and its target benefits with a different perspective. Here are a few:

Clone this wiki locally