VIPER architecture using RxSwift

VIPER architecture

VIPER stands forView-Interactor-Presenter-Entity-Router this pattern is highly scalable and has a brilliant separation of concerns. One feature, one module. For each module VIPER has five (sometimes four) different classes with distinct roles. No class go beyond its sole purpose. These classes are following.

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

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

Interactor: Have business logics of an app. Primarily make API calls to fetch data from a source. Responsible for making data calls but not necessarily from itself.

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

Entity: Contains plain model classes used by interactor.

VIPER — View-Interactor-Presenter-Entity-Router

VIPER Implementation

Viper is a delegate driven architecture. So, most of the communication between different layers executes through delegation. One layer calls another through a protocol. Calling layer just calls a function from a protocol. Listening layer conforms to that protocol and implements the function.

A naming convention is followed to name the protocols used for the communication between layers. Like ‘viewToPresenterProtocol’ . So, it is a ‘protocol’ which will be implemented by ‘the presenter’ to listen what the ‘view’ has to say.

  • PresenterToViewProtocol : Presenter calls, View listens. 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.
  • PresentorToInterectorProtocol : Presenter calls, Interactor listens.
  • PresenterToRouterProtocol : Presenter calls, Router listens.

App Flow

View has a reference of ‘ ViewToPresenterProtocol’ to access the ‘Presenter’ and Presenter conforms to ‘ PresenterToViewProtocol’. In View’s viewDidLoad() it calls the function updateView() of the protocol which is implement in Presenter that confirms to the protocol.

// View 
var presenter: ViewToPresenterProtocol?
override func viewDidLoad() {        
super.viewDidLoad();
presenter?.viewDidLoad(tableView: tableView)
}

Presenter conforms to ‘ ViewToPresenterProtocol’. So, it implements the function viewDidLoad(tableView: )

var interector: PresentorToInterectorProtocol?
func viewDidLoad(tableView:UITableView) {
interector?.fetchMovies();
}

inside viewDidLoad() presenter tells the interactor to fetch some movies. Interactor conforms to ‘PresentorToInterectorProtocol’ . So it implements fetchMovies(). This function tries to make a network call and fetch movies data. It has a reference from ‘InterectorToPresenterProtocol’ to access back the ‘Presenter’.

//Interactor
var presenter: InterectorToPresenterProtocol?

if the network call successfully have fetched the movies data it calls the following functions.

presenter?.loadMoviesFinished()

and if it errors out

presenter?.loadMoviesFailed()

Presenter also conforms to ‘ InterectorToPresenterProtocol’. So it implements loadMoviesFinished() and loadMoviesFailed() functions.

//presenter
func loadMoviesFinished() {
view?.showMovies()
}
func loadMoviesFailed(){
view?.showError()
}

View conforms to ‘ PresenterToViewProtocol’. Thus it implements showNews() and showError(). In these two functions view populate the view with the fetched data or the error.

VIPER architecture using RXSwift

RxSwift

“RxSwift is the reactive extension for Swift and can be found for free at https://github.com/ReactiveX/RxSwift.”

RxSwift is based on reactive programming, so what does that mean?

In computing, reactive programming is a programming paradigm oriented around data flows and the propagation of change. This means that it should be possible to express static or dynamic data flows with ease in the programming languages used, and that the underlying execution model will automatically propagate changes through the data flow. — Wikipedia

There’s a high probability that you didn’t understand anything of this paragraph after reading it. May be it would be better to understand with the following example:

Imagine you have three variables ( a,b,c ) like :

var a: Int = 1
var b: Int = 2
var c: Int = a + b // output 3

Now if we change a from 1 to 2 and we print c its value remains 3.But things are different in reactive world and c value’s is depend on a and b it means if you change a from 1 to 2 c value is change from 3 to 4 automatically and its not necessary to change it yourself.

Let’s look at RxSwift basics:

In RxSwift (and of course Rx ) world everything is stream of events ( including UI events , network requests , …). The main things in RxSwift are Observable and Observers.

Observable

An Observable is something which emits notifications of change.

Observer

An Observer is something which subscribes to an Observable, in order to be notified when it has changed

In Rx world for every observable in its persistent time it can emits 0 to … number of events which these events are enum consist of there 3 probable values:

  1. .next(value: T)

2. .error(error: Error)

3. .completed

If we want to cancel a subscription and unsubscribe from an observable we can call dispose method or if you want this method called when your view deinits you should make variable with DisposeBag type and this variable do the work for you when your class deinitilized. I must say if you don’t remember this your subscribers will make memory leak☠️💀.

Convert Protocol VIPER architecture to RXSwift VIPER

To convert Protocol approach using RxSwift, the easiest way is to change Protocols to Observables the class having the reference of protocol can have a reference of Observable(that can be simple observable, Variable or any Subject) and the class that conforms to protocol can subscribe to the desired observable. We can name these observable references as per the naming convention of protocols. For example View has a reference of PublishSubject named ‘ViewToPresenterProtocol’ and presenter can subscribe to this observable at the time of initialisation.

// View
var ViewToPresenterSubject: PublishSubject<UITableView?>?
override func viewDidLoad() {        
super.viewDidLoad();
ViewToPresenterSubject?.onNext(tableView)
}

Presenter becomes the subscriber of this observable subject at the time of initialising the presenter.

//Presenter 
func subscribeToVariable(_ subject: PublishSubject<UITableView?>) {
subject.subscribe(onNext: { (event) in
if event != nil {
self.viewDidLoad(tableView: tableView)
},
onCompleted: {
print("completed")
})
.disposed(by: disposeBag)
}

Now Presenter is the subscriber of ‘ ViewToPresenterSubject’. So, it will call viewDidLoad(tableView: ) when subject fires the onNext event from viewDidLoad of View.

In Rx approach Presenter will have ‘PresentorToInterectorSubject’ and it will fire onNext event from viewDidLoad function.

//Presenter 
var PresentorToInterectorSubject: PublishSubject<Void>?
func viewDidLoad(tableView:UITableView) {
PresentorToInterectorSubject?.onNext(());
}

Interactor will subscribe to this Observer.

//Interactor
func subscribeToVariable(_ subject: PublishSubject<Void>) {
subject.subscribe(onNext: { (event) in
self.fetchMovies()
onCompleted: {
print("completed")
})
.disposed(by: disposeBag)
}

inside viewDidLoad() when presenter calls onNext on PresentorToInterectorSubject, the onNext block in the subscription is called, which then call fetchMovies() function. As previously this function makes a network call and fetch movies data.

Presenter also has a reference of ‘InterectorToPresenterSubject’

//Interactor
var InterectorToPresenterSubject: PublishSubject<Void>?

InterectorToPresenterSubject is again subscribed by the Presenter.

//Presenter
func subscribeToVariable(_ subject: PublishSubject<Void>) {
subject.subscribe(onNext: { (event) in
self.loadMoviesFinished()
}),
onError: {
self.loadMoviesFailed()
}),
onCompleted: {
print("completed")
})
.disposed(by: disposeBag)
}

if the network call successfully have fetched the movies data it calls onNext event on the subject.

InterectorToPresenterSubject.onNext(())

and if it errors out

InterectorToPresenterSubject.onError(ToPresenterError.error)

Error can be defined as an enum extending from Error

public enum ToPresenterError: Error {
case error
}

when ‘InterectorToPresenterSubject.onError’ is called the onError block in subscription is called, which is calling loadMoviesFailed() function.

Finally Presenter has reference for PresenterToViewProtocol and View becomes subscriber for it.

// View 
func subscribeToVariable(_ subject: PublishSubject<Void>) {
subject.subscribe(onNext: { (event) in
self.reloadTableViewData()
}),
onError: {
self.showError()
}),
onCompleted: {
print("completed")
})
.disposed(by: disposeBag)
}

OnError event is fired from loadMoviesFailed() function of Presenter and onNext is fired from loadMoviesFinished function of Presenter.

func loadMoviesFinished() {
PresenterToViewSubject.onNext(())
}
func loadMoviesFailed() {
PresenterToViewSubject.onError(ToPresenterError.error)
}

In every subscription there is a disposed function as well, it will dispose of the subscription using a dispose bag, when the respective class is deinitilized the subscription is automatically disposed of. In this way subscriber will not leak memory.

Conclusion

Just like any other design pattern VIPER is self-explanatory. One needs to get one’s hands dirty to understand the whole picture. My advice will be to first start with creating a very basic app with VIPER architecture, and then follow the steps explained above to convert the protocol implementation to RxSwift Observables.

Happy coding :)