VIPER Design Pattern in Swift for iOS Application Development.

Everything that has a beginning, has an end -Gautama Buddha. Image Source: Screenshot taken from the movie “The Matrix Revolutions”

Design patterns are God’s gift to software developers. These are techniques that minimize code duplication, prevent high coupling, and standardize a common way of writing code that provides a general solution for recurring situations while developing software. In this story, we will get familiar with a design pattern called VIPER (View, Interactor, Presenter, Entity, and Router.) for iOS development.

Prerequisites: Before starting about VIPER, please make sure you know about architectural design patterns and delegation patterns.

What is Viper?

View: Class that has all the code to show the app interface to the user and get their responses. Upon receiving a response View alerts the Presenter.

Presenter: Nucleus of a module. It gets user response from the View and works accordingly. The only class to communicate with all the other components. Calls the router for wire-framing, Interactor to fetch data (network calls or local data calls), view to update the UI.

Interactor: Has the business logic of an app. e.g if business logic depends on making network calls then it is Interactor’s responsibility to do so.

Router: Does the wire-framing. Listens from the presenter about which screen to present and executes that.

Entity: Contains plain model classes used by the Interactor.

Below shows a simple diagram of VIPER

Viper Architecture

Viper with Example

Viper is a delegation-driven architecture. So, most of the communication between different layers executes through delegation. One layer calls another through a protocol. The calling layer calls a function from a protocol. The listening layer conforms to that protocol and implements the function.

Below I will explain how I have implemented VIPER in one of my sample projects. I suggest you open the project in GitHub and go through it while reading the explanation.

Protocols

A naming convention is followed to name a protocol. e.g, ‘viewToPresenterProtocol’. So, it is a ‘protocol’ that will be implemented by ‘the presenter’ to listen to what the ‘view’ has to say.

  • PresenterToViewProtocol : Presenter calls, View listens. The presenter receives a reference from this protocol to access View. View conforms to the protocol.
  • ViewToPresenterProtocol: View calls, Presenter listens.
  • InteractorToPresenterProtocol: Interactor calls, Presenter listens.
  • PresentorToInteractorProtocol: Presenter calls, Interactor listens.
  • PresenterToRouterProtocol: Presenter calls, Router listens.

Also, our protocol names must be different for different modules. One way to achieve this is to add the module name as a prefix. So the format could be <Module-Name><Protocol-Name> e.g if the module name is Login then view to presenter protocol name will be LoginViewToPresenterProtocol. Our example project follows this convention which we will see further in the story.

App Flow

// Viewvar presenter: LiveNewsListViewToPresenterProtocol?override func viewDidLoad() {        
super.viewDidLoad()
presenter?.updateView()
}

Presenter on the other hand conforms to LiveNewsListViewToPresenterProtocol. So, it implements the function updateView().

// Presentervar interactor: LiveNewsListPresentorToInteractorProtocol?func updateView() {
interactor?.fetchLiveNews()
}

Inside updateView() presenter tells the interactor to fetch some live news data.

Interactor conforms to LiveNewsListPresentorToInteractorProtocol . So it implements fetchLiveNews() function. This function makes a network call and fetch data. It has a reference from LiveNewsListInteractorToPresenterProtocol to access the Presenter.

// Interactorweak var presenter: LiveNewsListInteractorToPresenterProtocol?

If the network call successfully has fetched the data it calls the following function.

// Interactorguard let articles = newsResponse.articles else { return }                    self.news = articles
self.presenter?.liveNewsFetched()

if not

// Interactorself.presenter?.liveNewsFetchedFailed()

Now presenter also conforms to LiveNewsListInteractorToPresenterProtocol. So it implements these functions.

// Presenterfunc liveNewsFetched(news: [LiveNewsModel]) {
view?.showNews()
}
func liveNewsFetchedFailed(){
view?.showError()
}

So it tells the view whether to show news or to show an error.

Now, View conforms to LiveNewsListPresenterToViewProtocol. Thus it implements showNews() and showError(). In these two functions view populates the view with the fetched data or the error.

// Viewfunc showNews() {
tableView.reloadData()
}
func showError() {
//write error showing code here
}

The Entity Layer

// Viewfunc tableView(_ tableView: UITableView, cellForRowAt indexPath:   IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LiveNewsTableViewCell", for: indexPath) as? LiveNewsListTableViewCell
let row = indexPath.row
let news = presenter?.getNews(index: row)
guard let title = news?.title, let author = news?.author, let description = news?.description else {
return cell ?? UITableViewCell()
}
cell?.setCell(title: title, author: author, description: description) return cell ?? UITableViewCell()
}

Here at this below line, the data is requested from the presenter.

// Viewlet news = presenter?.getNews(index: row)

Then Presenter gets it from the Interactor.

// Presentervar news: [LiveNewsModel]?func getNews(index: Int) -> LiveNewsModel? {
return interactor?.news?[index]
}

So the main point here is that only the Interactor will have an instance of the Entity.

Router

We have discussed earlier that in VIPER architecture every single feature has a single module and a module contains those five layers. A presenter calls the router to create a new module. Then router first initiate all the layer class and returns the module.

In my sample project, there is no module change happening. But routing does happen when the app first time launches. So inside AppDelegate’s didFinishLaunchingWithOptions(), router’s createModule() function is called. It returns a module. UIWindow class then shows the View of that module.

Why and When to use VIPER

VIPER should be used when an application’s requirements are very well-formed. Working with constantly changing requirements may create confusion and messed-up codes. So, it should not be used in small projects as MVP or MVC will suffice. Also, VIPER should be used if all the developer of the project fully understands the pattern.

VIPER Tools

Conclusion

Happy coding :)

Long live sacred Bangladesh.

Bangladesh is a world of metaphor, of high and low theater, of great poetry and music. You talk to a rice farmer and you find a poet. You get to know a sweeper of the streets and you find a remarkable singer.

Jean Houston

Reference :

  1. https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52
  2. https://medium.com/@ankoma22/the-good-the-bad-and-the-ugly-of-viper-architecture-for-ios-apps-7272001b5347
  3. https://github.com/MindorksOpenSource/iOS-Viper-Architecture/tree/master/iOS-Viper-Architecture
  4. https://sourcemaking.com/design_patterns

Software Engineer (iOS) @ Mindvalley