In this article I will talk about the architecture of iOS applications - Clean Swift . We consider the main theoretical points and analyze the example in practice.
Theory
To begin with, let's look at the basic terminology of the architecture. In Clean Swift, an application consists of scenes, i.e. Each screen of the application is one scene. The main interaction in the scene goes through a sequential loop between the components of the ViewController -> Interactor -> Presenter . This is called the VIP loop. ')
The bridge between the components is the Models file, which stores the transmitted data. There is also Router , which is responsible for the transfer and transfer of data between the scenes, and the Worker , which takes a part of the Interactor’s logic.
View
Storyboards, XIBs or UI elements written through code.
Viewcontroller
Responsible for configuration and interaction with the View . The controller should not contain any business logic, interaction with the network, computing, and so on. Its task is to process events from View , display or send data (without processing and checks) to Interactor .
Interactor
It contains the business logic of the scene.
It works with network, database and device modules.
Interactor receives a request from ViewController (with data or empty), processes it and, if required, sends new data to the Presenter .
Presenter
Is engaged in the preparation of data for display.
As an example, add a mask to a phone number or make the first letter in the title capitalized. It processes the data received from Interactor and then sends it back to the ViewController .
Models
A set of structures for transferring data between the components of the VIP loop. Each cycle cycle has 3 types of structures:
Request - Data structure (text from TextField, etc.) for transfer from ViewController to Interactor
Response - A structure with data (downloaded from the network, etc.) to be transferred from Interactor to Presenter
ViewModel - A structure with processed data (text formatting, etc.) in Presenter for transfer back to the ViewController
Worker
Unloads Interactor , taking away part of the business logic of the application, if Interactor is growing rapidly.
You can also create common for all scenes Workers , if their functionality is used in several scenes.
As an example, in Worker you can make out the logic of working with a network or database.
Router
In Router , all the logic responsible for the transitions and data transfer between scenes is made.
To clarify the picture of the VIP cycle, I will give a standard example - authorization.
The user entered his login and password, clicked on the authorization button
IBAction is triggered by ViewController , after which a structure is created with the user data entered in TextFields (Models -> Request)
The created structure is passed to the fetchUser method in Interactor.
Interactor sends a request to the network and receives an answer about the success of authorization
Based on the received data, it creates a structure with the result (Models -> Response) and is passed to the presentUser method in the Presenter.
Presenter formats the data as necessary and returns it (Models -> ViewModel) to the displayUser method in the ViewController
ViewController displays the received data to the user. In the case of authorization, an error may be displayed or a transition to another scene may work using the Router.
Thus, we get a unified and consistent structure, with the division of responsibilities into components.
Practice
And now we will analyze a small practical example that will show how the VIP cycle goes. In this example, we simulate data loading when opening a scene (screen). I marked the main sections of the code with comments.
The entire VIP cycle is tied to protocols, which provides the possibility of replacing any modules without disrupting the operation of the application. For ViewController , the DisplayLogic protocol is created, and a link to it is sent to the Presenter for subsequent call. For Interactor , two BusinessLogic protocols are created, responsible for calling methods from ViewController , and DataSource , for storing data and transferring another scene through Router to Interactor . Presenter subscribes to the PresentationLogic protocol, to be called from Interactor . The connecting element of all this is Models . It contains the structures through which information is exchanged between the components of the VIP cycle. With it, and begin the analysis of the code.
Models
In the example below, for the Home scene, I created the HomeModels file, which contains a set of requests for the VIP loop. The FetchUser request will be responsible for uploading user data, which we will consider further.
When the class is initialized, we create instances of the Interactor and Presenter classes of this scene and set dependencies between them. Further, in the ViewController , only the Interactor link remains. With this link we will create a request to the fetchUser (request :) method in Interactor , to start the VIP loop.
Here you should pay attention to how the query to Interactor . In the loadUserInfromation () method, we create an instance of the Request structure, where we pass the initial value. It can be taken from TextField , tables, and so on. An instance of the Request structure is passed to the fetchUser (request :) method, which is in the Interactor'sBusinessLogic protocol.
An instance of the Interactor class contains a reference to the PresentationLogic protocol, under which Presenter is signed.
The fetchUser (request :) method can contain any logic for loading data. For example, I just created constants with supposedly received data.
In the same method, an instance of the Response structure is created and filled with the parameters obtained earlier. The response is passed to PresentationLogic using the presentUser (response :) method. In other words, here we got the raw data and passed it to Presenter for processing.
It has a link to the DisplayLogic protocol, under which ViewController is signed. It does not contain any business logic, but only formats the data before display. In the example, we formatted the phone number, prepared an instance of the ViewModel structure, and transferred it to the ViewController , using the displayUser (viewModel :) method in the DisplayLogic protocol, where the data is already being displayed.
With this architecture, we were able to distribute responsibilities, improve the convenience of testing the application, introduce the substitutability of individual implementation sections and the standard for writing code for teamwork.