Understanding VIPER Architecture

Pınar Koçak
4 min readApr 21, 2022

--

“In the last couple of years, several new patterns emerged, all praising to make a developer’s life as easy as never before. By separating certain parts of the codebase, each of these patterns tries to make code more readable, easier to test, and eventually more maintainable.”

Photo from raywenderlich.com

There are wide variety of architecture design patterns such as MVI, MVP, MVVM etc. All of them have their own advantages and disadvantages. According to size of your project, you can choose one of them. In this article, I will try to explain VIPER design pattern with coding. Also you can read about other architecture design patterns in my another article here.

First of all, I am going to talk about VIPER just a little bit.

What’s VIPER?

VIPER is an application architecture. It reduces coding complexity, especially in large projects. The purpose of the architecture is to separate the operational codes within the project and modules and regularization. It is basically the use of protocol because interlayer communication is provided by Protocols in VIPER design pattern.

Source

View

It is our ViewController and it’s responsibility is showing data to user. Here we only use the data from the presenter. No other action is taken.

Interactor

We can say that it acts as the ViewModel in the MVVM design pattern. It is the part of the application that we call Bussines Logic. UI operations are not performed here. Fetch, Update, API etc. operations take place here.

Presenter

It is the bridge between View and Interactor. This layer should not contain UI or bussines logic operations.

Entity

It is the Model part of the application. Data models related to the application are found here. This part cooperates only with Interactor.

Router

This layer is the layer that allows us to determine when the application’s pages are shown. Router helps to communicate other layers with each other. We describe our Protocols in here.

Let’s take a closer look. I’ve tried to explain VIPER with simple iOS app.

First, we are going to create our View. In here you can see operation buttons, result label and input textFields. I used storyboard to create my view.

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var txtFieldNumber2: UITextField!
@IBOutlet weak var txtFieldNumber1: UITextField!
@IBOutlet weak var labelResult: UILabel!

var presenterObj: ViewToPresenterProtocol?

override func viewDidLoad() {
super.viewDidLoad()
labelResult.text = "0"
Router.createModule(ref: self)
}

@IBAction func btnAdd(_ sender: Any) {
if let number1 = txtFieldNumber1.text, let number2 = txtFieldNumber2.text {
presenterObj?.addition(num1: number1, num2: number2)
}
}

@IBAction func btnMultiply(_ sender: Any) {
if let number1 = txtFieldNumber1.text, let number2 = txtFieldNumber2.text {
presenterObj?.multiplication(num1: number1, num2: number2)
}
}
}

extension ViewController: PresenterToViewProtocol {
func sendDataToView(result: String) {
labelResult.text = result
}
}

Protocols are important in this architecture. I will examine the protocols under two different names, carrier protocols and main protocols.

In this application InteractorToPresenterProtocol and PresenterToViewProtocol are our carrier protocols. These protocols help us to carry the final data formed in the interactor from the presenter to the view. That’s why we named them iteractor to presenter and presenter to view protocol.

ViewToPresenterProtocol and PresenterToInteractorProtocol are main protocols, so they includes not only functions but also properties. We use these protocols to send data from view to interactor through presenter.

import Foundation

protocol InteractorToPresenterProtocol {
func sendDataToPresenter(result: String)
}

protocol PresenterToViewProtocol {
func sendDataToView(result: String)
}

protocol ViewToPresenterProtocol {
var view: PresenterToViewProtocol? { get set }
var interactor: PresenterToInteractorProtocol? { get set }

func addition(num1: String, num2: String)
func multiplication(num1: String, num2: String)
}

protocol PresenterToInteractorProtocol {
var presenter: InteractorToPresenterProtocol? { get set}

func add(num1: String, num2: String)
func multiply(num1: String, num2: String)
}

protocol PresenterToRouterProtocol {
static func createModule(ref: ViewController)
}

There is no need to define variables in carrier protocols. They carry data with methods. However, in the main protocols, we need to trigger data by defining variables.

Note that in the class to be triggered, there must be an object from the triggered class.

Then we are going to create other VIPER elements which are interactor and presenter.

import Foundation

class Interactor: PresenterToInteractorProtocol {
var presenter: InteractorToPresenterProtocol?

func add(num1: String, num2: String) {
if let s1 = Int(num1), let s2 = Int(num2) {
let sum = s1 + s2
presenter?.sendDataToPresenter(result: String(sum))
}
}

func multiply(num1: String, num2: String) {
if let s1 = Int(num1), let s2 = Int(num2) {
let mul = s1 * s2
presenter?.sendDataToPresenter(result: String(mul))
}
}
}
import Foundation

class Presenter: ViewToPresenterProtocol {
var view: PresenterToViewProtocol?
var interactor: PresenterToInteractorProtocol?

func addition(num1: String, num2: String) {
interactor?.add(num1: num1, num2: num2)
}

func multiplication(num1: String, num2: String) {
interactor?.multiply(num1: num1, num2: num2)
}
}

extension Presenter: InteractorToPresenterProtocol {
func sendDataToPresenter(result: String) {
view?.sendDataToView(result: result)
}
}

In router, we make the authorization that enables all protocols to work.

import Foundation

class Router: PresenterToRouterProtocol {
static func createModule(ref: ViewController) {
let presenter = Presenter()

ref.presenterObj = presenter

ref.presenterObj?.interactor = Interactor()
ref.presenterObj?.view = ref

ref.presenterObj?.interactor?.presenter = presenter
}
}

Note that this architecture also has its own disadvantages such as difficulty in using it in small projects and causing complexity because of many folders and delegates in the project.

Here it is. We completed our basic iOS application using VIPER design pattern. You can reach all code from here.

I hope it was clear enough for you to understand VIPER application architecture design pattern. I also want to thank Kasım Adalan to teach me that design pattern. See you in next post.

--

--