VIP Architecture in iOS
An overview of getting started with Clean Architecture
Hello 😎!
In this article, we are going to discuss how to get started with VIP Architecture in iOS. We shall begin by looking at certain theoretical backgrounds to understand the basic working and data-flow in VIP. Following which we will dive into some real code.
Topics that shall be covered are —
- Why VIP?
- VIP: View Controller, Interactor, Presenter
- VIP Cycle and Data flow
- Implementing VIP in iOS
Why VIP?
To begin with, you may have worked with various system architectures such as MVC, MVVM, ReactiveCocoa, or VIPER which have been “good” and did a great job until recently. These architectures have been helpful in building and publishing various apps. However, they have not been “good” in efficiently managing the problems of scalability and maintenance.
This is due to the underlying issues in the design and data flow patterns of these architectures that make them challenging and nonreliable often leading to Massive View Controller. Further, there may be bugs and difficulties in adding new features which makes the use of these architectures more cumbersome.
Clean VIP Architecture is what offers a solution to the above-mentioned problems.
VIP: View Controller, Interactor, Presenter
VIP is Uncle Bob’s Clean Architecture. It is one of those system architectures that follow clean architecture guidelines about system design, component design, data flow between different system layers, and others. It consists of three core components:
- ViewController: It is a UIViewController that we encounter frequently with the mere difference that in VIP it has only two responsibilities, namely, getting user inputs and rendering UI. In addition, it also holds a
strong
reference to Interactor. - Interactor: In VIP, Interactor is a
concrete class
with the functions of making various API calls and maintaining data and business logic. It holds astrong
reference to the Presenter. - Presenter: The presenter is also a
concrete class
that holds aweak
reference to Controller. It performs the functions of creating and passing data to ViewController via ViewModels and validating data and actions for ViewController.
Hence, the responsibilities in VIP are nicely divided into various classes leading to a clear separation of UI and business logic, unlike other architectures.
Note that a few other entities like — Models and Routers that facilitate navigations and data maintenance have not been broadly discussed here.
VIP Cycle and Data flow
The VIP cycle and data flow is as follows—
ViewController → Interactor → Presenter → ViewController
ViewController
takes user inputs and passes them toInteractor
in form of requests.Interactor
processes these requests (validates and executes them) and passes the response to thePresenter
Presenter
processes these responses (validates and creates ViewModels) and passes them toViewController
to update/render UI.
From above, it is clear that the data flow in VIP is uni-directional, from View -> Interactor -> Presenter -> View. This way VIP tackles certain problems that arise in bi-directional data flow architectures like MVC, MVVM, and others.
VIP in iOS: Implementation
Now comes the final step of implementing VIP in an iOS Project.
For simplicity, the example is restricted to only one view, which displays a list of Movies that have an imdbRating > 8.0
. This is achieved via a UITableView and a set of prefetched movie data stored in a JSON file in the App bundle.
Models — Movie.swift
In order to display the above data, we will create Movie
, a model that will map data for each movie.
Worker — FileReader.swift
This is a Worker class that reads data from the static JSON file saved in the App bundle.
FileReader
is a Worker that has a static method getMovies(:)
to read data from JSON files and send Result
in a callback
.
ViewController — MoviesListController.swift
This is a UIViewController
class that controls the UI of the App.
Notice that the controller in the above code holds an optional
reference of the interactor
, which is used to pass user and data requests from the controller to interactor as is evident from the usage of the method viewWillAppear(:)
.
Besides, MoviesListController
also has a render(props:)
which is the only method responsible for updating the view as is suggested by the theory. This helps in debugging and maintaining update logics for the view.
Interactor —MoviesListInteractor.swift
The following snippet shows the interactor
performing its core responsibilities — getMovies(:)
to get data and processMovies(:)
to implement business logic.
Here, interactor
fetches data for movies
, processes it and then triggers an update in the presenter
. Hence, passing response from interactor -> presenter
Presenter — MoviesListPresenter.swift
This section shows the presenter
, performing its core responsibility— updating controller
with the new data passed to it.
It is worth noting how in the method updateView(:)
, presenter
reads the current state of controllers viewProps
and updates only the required data and then triggers the render(:)
method that would start the view update. So, passing data from presenter -> view
. With this, the VIP cycle which is a uni-directional
data flow is completed.
Router — Router.swift
In VIP, Router is a class facilitating navigation from one view to another. Generally, each view has its own Router
but, it is not always necessary as there can be a global
Router class that may be divided into various sub-routers whilst maintaining the navigation stack. In the example below, a global Router
is created that has its own navigationController
.
Observe how the method showMoviesListView()
is used to show the Movies list view. This method instantiates the controller, presenter, interactor and passes the reference of one entity to another. This is a very apt representation of the VIP cycle.
Once all the relations are established, the view is pushed onto the navigation stack which brings us to the end of VIP implementation.
The only thing left now is to call the startNavigation()
to start navigating and presenting views. This can be done either in AppDelegate
or SceneDelegate
classes. Based on my deploymentTarget
i.e. iOS 14.2, I have done that in SceneDelegate
.
This brings us to the end of the article. All that is left now is to run the App.
Hope that now you can try and create your own iOS Apps that follow the Clean VIP Architecture and play around with your code in this amazing way whilst noticing the immense scope of VIP.
If you want the complete source code of the above example, visit the Github repository given below—
See you soon! Until then,
Happy Coding!💻📱