Building an app with a smooth design and a great user experience is important, but there may be some other points where a developer should focus on during the development of an app. One of them, is choosing an architecture, which will improve the maintainability of the code. Choosing for a good architecture also makes it possible to add new features to existing software easier.
During research for a new architecture, I came across Clean Swift (also known as VIP), which is based on the Clean Architecture book written by Uncle Bob. In this blogpost, I will explain the basics of the architecture.
The VIP cycle
The Clean Swift architecture is using a VIP cycle to help you separate logic in your application. The VIP cycle consists of a ViewController, Interactor and a Presenter. All classes are responsible for some logic. The ViewController is responsible for the display logic, the Interactor is responsible for the business logic and the Presenter is responsible for the presentation logic. The image below describes the flow of the VIP cycle.
The ViewController is the first class where the action is triggered. The class is responsible for managing the views in the ViewController. In the ViewController, all the outlets and IBAction functions should be listed.
As soon as an action in the ViewController started, the ViewController will pass that action to the Interactor. The Interactor is the class where all the use cases should be implemented. By doing this, the Interactor is the class which contains all the business logic. This is a big benefit when writing unit tests, because when testing the all interactors, all the business logic in your app is tested.
The Interactor is responsible for handling the request and will return an object to the Presenter. The Presenter is the class which is responsible for presenting the object which is generated by the Interactor. The Presenter will parse that object to a ViewModel object and return an object to the ViewController to display.
Using the Clean Swift architecture, you know exactly which logic should be located in which class. This makes your code more maintainable, because when you need to solve a bug or want to add more functionalities, you know exactly where in your code the change should be made.
During the VIP cycle, each class will add a data object when requesting an action from the other class in the cycle. When the ViewController ask the interactor to request an action from the Interactor, the ViewController will add an ‘Request’ object. This object contains all the data the interactor needs to do the business logic.
The Interactor will handle the request. Once the data has been processed, it will return a ‘Response’ object to the Presenter. The Presenter will parse the data which is needed to a ‘ViewModel’ object, which will be send to the ViewController. When the ViewModel is received by the ViewController, the ViewController only needs to update the UI elements with the data in the ViewModel.
There may be situations in your app that the ViewController will present another ViewController. In Clean Swift, navigating between ViewControllers is done by a Router.
If there are navigation options available for the ViewController, a Router class is added to the ViewController. The Router class contains all the navigation options where that specific ViewController can navigate trough. By doing this, almost each VIP cycle will have a Router, which makes it clear what navigation options a ViewController has.
Presentors are responsible for the presentation logic. When a screen transition will take place, the ViewController needs to ask this to the Interactor and then the Interactor needs to ask this to the Presentor. From there, the Presentor will decide that the ViewController may route to the next ViewController using the Router.
When having all business logic located in the Interactor, there may happen a situation where the Interactor will be a very large class. To prevent this, an Interactor can make use of multiple workers. A Worker is a helper of the Interactor, which can help receiving data.
Worker are responsible for creating objects and doing network calls. Besides that, a Worker can be used to implement Third Party SDKs in your application. For example, if you use Alamofire for doing network requests, but do all the network requests in workers, the Alamofire SDK only needs to be imported in the worker.
Workers must be generic, which means multiple interactors can use them if needed to handle data.
Implement Clean Swift in your app
Above information about Clean Swift is just the description about how the architecture is working, but is not describing the implementation of the Clean Swift architecture in your app.
If you want to start with the implementation of the Clean Swift architecture, you may want to use Xcode templates for Clean Swift, which is described in this blog post. Also take a look at the example project CleanStore by Raymond Law, to get an impression on how you can implement Clean Swift.
In the future, I will write a blog post about the implementation I did for the Countdown app I created last year. The Countdown app is using Apple CloudKit SDK to save events from users in their iCloud database, which is a perfect example to explain the VIP cycle. Coming soon!