Getting Started with the VIPER Architecture Pattern for iOS Application Development
Tags: ios, swift, viper, mobile
Published: 2022-11-20 13:43:49


When you are planning to build an app, one of the most important decisions is to choose how to structure your app’s core.

Better saying, you need to decide which architecture you should adopt to build all your screens, features, and contexts. You need to know how to organize your app in order to make it maintainable for the long term, testable, scalable, and understandable by anyone who enters the project sometime later. In this article, we will get familiar with a design pattern called VIPER (View, Interactor, Presenter, Entity, and Router.) for iOS development.

**What is VIPER?**

VIPER is an architectural pattern like MVC or MVVM, but it separates the code further by single responsibility.
One feature, one module. For each module, VIPER has five different classes with distinct roles. No class goes beyond its sole purpose.

Each of the letters in VIPER stand for a component of the architecture: View, Interactor, Presenter, Entity and Router.

- **View** is the user interface. This layer is the ViewController together with the UIView(or xib/storyboard)

- **Interactor** contains business logic related to the data (Entities) or networking, like creating new instances of entities or fetching them from the server. For those purposes you’ll use some Services and Managers which are not considered as a part of VIPER module but rather an external dependency

- **Presenter** is directing data between the view and interactor, taking user actions and calling to router to move the user between views.The only class to communicate with all the other components.

- **Entity** is your plain data objects, not the data access layer, because that is a responsibility of the Interactor.

- **Router** handles navigation between the VIPER modules.



![Image VIPER](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5103nmzqxl6u98z5fca.png)


Below I will explain an example of VIPER

**Protocols**
I have created a separate file for all the protocols

```
protocol NewsListView: AnyObject {
}

protocol NewsListPresenter: AnyObject {
    func viewDidLoad(view: NewsListView)
}

protocol NewsListInteractorInput: AnyObject {
}

protocol NewsListInteractorOutput: AnyObject {
}

protocol NewsListRouter: AnyObject {
}

protocol NewsListRepo: AnyObject {

}
```
As you can see from the above code, this is the main contract agreement between VIPER layers.

**Presenter**

PresenterImplementation is an implementation of NewsListPresenter protocol and confirm the NewsListInteractorOutput.

In this layer presenter has a reference object from **View**, **Router** and **Interactor**

```
final class NewsListPresenterImplementation: NewsListPresenter{

    private weak var view: NewsListView?
    private let router: NewsListRouter
    private let interactor: NewsListInteractorInput

    init(router: NewsListRouter, interactor: NewsListInteractorInput) {
        self.router = router
        self.interactor = interactor
    }

    func viewDidLoad(view: NewsListView) {
        self.view = view
    }
}

extension NewsListPresenterImplementation: NewsListInteractorOutput {

}
```
**Interactor**
Interactor is an implementation of NewsListInteractorInput protocol

NewsListRepo is responsible to fetch the data from network or Data provider

```
final class NewsListInteractor: NewsListInteractorInput {

    weak var output: NewsListInteractorOutput?

    private let repo: NewsListRepo

    init(repo: NewsListRepo) {
        self.repo = repo
    }
}
```

**View**
View is a UIViewController with a confirmation of NewsListView protocol and it has reference to the presenter

```
final class NewsListViewController: UIViewController, NewsListView {

    private let presenter: NewsListPresenter

    init(presenter: NewsListPresenter) {
        self.presenter = presenter

        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        presenter.viewDidLoad(view: self)
    }
}
```
**Entity**

```
struct News {
    let title: String
    let url: URL
}
```
**Router**

```
final class NewsListRouterImplementation: NewsListRouter {

    weak var viewController: UIViewController?

}
```
Now we need to update our VIPER module to fetch the news data, yes as you are thinking right now, we need to update our contract protocols first

```
protocol NewsListView: AnyObject {
    func show(newsList: [News])
}

protocol NewsListPresenter: AnyObject {
    func viewDidLoad(view: NewsListView)
}

protocol NewsListInteractorInput: AnyObject {
    func fetchNewsList()
}

protocol NewsListInteractorOutput: AnyObject {
    func fetchNewsListSuccess(newsList: [News])
    func fetchNewsListFailure(error: Error?)
}

protocol NewsListRepo: AnyObject {
    func fetchNewsList(completion: @escaping ([News]?, Error?) -> Void)
}

protocol NewsListRouter: AnyObject {
}
```
Let’s now add implementation for theses added funcs in the protocols


**Interactor**

```
final class NewsListRepoImplementationl: NewsListRepo {
    func fetchNewsList(completion: @escaping ([News]?, Error?) -> Void) {
        // Fetch the data with completion
    }
}
```

```
final class NewsListInteractor: NewsListInteractorInput {
    
    weak var output: NewsListInteractorOutput?

    private let repo: NewsListRepo

    init(repo: NewsListRepo) {
        self.repo = repo
    }
    
    func fetchNewsList() {
        repo.fetchNewsList { news, error in
            if let newsList = news {
                self.output?.fetchNewsListSuccess(newsList: newsList)
            } else {
                self.output?.fetchNewsListFailure(error: error)
            }
        }
    }
}
```
**Presenter**

```
final class NewsListPresenterImplementation: NewsListPresenter{

    private weak var view: NewsListView?
    private let router: NewsListRouter
    private let interactor: NewsListInteractorInput

    init(router: NewsListRouter, interactor: NewsListInteractorInput) {
        self.router = router
        self.interactor = interactor
    }

    func viewDidLoad(view: NewsListView) {
        self.view = view
        // Fetch the list from the interactor
        interactor.fetchNewsList()
    }
}

extension NewsListPresenterImplementation: NewsListInteractorOutput {
    func fetchNewsListSuccess(newsList: [News]) {
        self.view?.show(newsList: newsList)
    }
    
    func fetchNewsListFailure(error: Error?) {
        // show Error
    }
}
```
**View**

```
final class NewsListViewController: UIViewController, NewsListView {

    private let presenter: NewsListPresenter

    init(presenter: NewsListPresenter) {
        self.presenter = presenter

        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        presenter.viewDidLoad(view: self)
    }

    func show(newsList: [News]) {
        // show the news in the UI 
    }
}

```
Now, we are fetching the news list from the **interactor** layer, then update the **presenter** with the result and the presenter is prepare the data for the View and boom pass it

Last piece from the puzzle here is to build our module, so I have created a builder class to launch my module

```
final class NewsListBuilder {

    func build() -> UIViewController {
        let router = NewsListRouterImplementation()
        let repo = NewsListRepoImplementation()
        let interactor = NewsListInteractor(repo: repo)
        let presenter = NewsListPresenterImplementation(router: router, interactor: interactor)
        let view = NewsListViewController(presenter: presenter)

        router.viewController = view
        interactor.output = presenter
        return view
    }
}
```

## Conclusion
VIPER is sounds complex in the beginning but it’s very clean architecture. It isolates each module from others. So changing or fixing bugs is very easy as you only have to update a specific module. Also for having a modular approach VIPER creates a very good environment for unit testing. As each module is independent of others, it maintains low coupling very well. So, dividing work among co-developers is also pretty simple.

My advice if you are going to using VIPER in your project, the smartest thing would be to use an automatic module structure generator. Otherwise creating files for modules will be a big hustle, There are few generators available online.

[VIPER Gen ](https://github.com/pepibumur/viper-module-generator?utm_source=swifting.io&utm_medium=web&utm_campaign=blog%20post)
[VIPER Code](https://github.com/iSame7/ViperCode?utm_source=swifting.io&utm_medium=web&utm_campaign=blog%20post)

**Thank you for reading! If you liked this article, please Like so other people can read it too :)**

Happy coding :v:

Reach me out [here](https://marwanayman.com/)