- You do not have to clone the current repository just follow step-by-step the instruction:
- brew install xcodegen
- Open terminal inside the folder where you want to start new project('Directory with project name will be created automaticly)
- run the comand:
bash <(curl -s https://raw.githubusercontent.com/chisw-ios/MVP-Coordinator/develop/setup.sh)
The skeleton of the project is based on the modular architecture MVP + C. It is based on a microservice idea, where each flow user will be a separate service. The principle of DependencyInjection is at the core of all dependencies. The directories in the project are divided into the following layers:
- ApplicationLayer - with the most essential services
- BusinessLogicLayer - where we place models for networking and databases, as well as services for each flow.
- Models - directory with networking and database models
- Services - directory for services and the main class Services (a service locator)
- AdditionalServices - common additional services (BiometricsService, FileService)
- DataBase - prepared database setup - RealmSwift
- ModuleServices - services for working with individual flows
- Networking - directory with classes for networking
- CoreLayer:
- Autogenerated - auto-generated resource files using SwiftGen (localization, colors, pictures, fonts)
- BaseClases - base classes (cell, controller)
- Configurations - configuration files for setting different schemes (development, staging, production)
- Constants - for storing global constants
- Coordinator - with base classes for coordinator and routing.
- Extension - various useful class extensions
- Generics - generics (for example, for working with datasource tables and collections)
- Helpers - various helpers (Keychain, Logger, Utils)
- Transitions - for custom transitions and animations
- PresentationLayer - layer for all flows with modules and controllers
- Resources - for storing core resources (localization, fonts, images, colors ๐ท)
- Supporting Files - system accompanying files
The application life cycle begins with the SceneDelegate, where the main DependencyProvider entity starts. It runs all our services and the main coordinator. (ApplicationLayer /). The coordinator pattern allows you to facilitate and decompose the routing of all screens within an application. The main coordinator of the ApplicationCoordinator defines the entry point of the application, on LoginFlow or MainFlow by using LaunchInstructo. For example, the demo project has two flows Auth and Main, and, accordingly, the services AuthService and UserService (BusinessLogicLayer / Services) that serve the flow. The Services class (BusinessLogicLayer / Services) is responsible for initializing networking, storage, and services for all flows.
Each module consists of an MVP (Model-ViewController-Presenter) architecture standard and it has own coordinator in addition to the module or userFlow. There is a main ApplicationCoordinator which contains subcoordinators. Each of them inherits from BaseCoordinator, which contains an array of all coordinators. In order to collect the main coordinators for entry points, it must be described in the CoordinatorFactoryProtocol protocol. Below there is a diagram that shows how we branch out subcoordinators.
To make creating MVPC modules convenient, there is an Xcode_Template_MVPC template in the root directory. You can add it and use it. Next, we'll discuss PresentationLayer. Let's analyze the module by taking the Auth module as an example:
- Auth.storyboard - it is recommended to use no more than 5 screens in one file. If more screens needed, we create new storyboards with relational links in order to avoid conflicts when merging branches. Rule of thumb: One person - one flow - one storyboard.
- AuthViewControllerFactory - an assembler, builder or factory that is responsible for assembling modules (controllers with presents)
- AuthCoordinator - responsible for routing between all screens of the module by means of transferring events from the controller to the presenter, and then to the coordinator. The idea is based on blocks, the description of the work is just below in the presenter.
- Login submodule:
- LoginViewController โ is responsible for working with the screen (UI, ViewLifeCycle)
- LoginPresenter - processing business logic from services, preparing data for display
- Access to each presentation goes through the LoginPresenterProtocol protocol which describes all actions that the controller can perform with the presentation
- Each presenter describes the routes that the LoginPresenterRoutes module can walk. This is a structure with blocks which we initialize in the coordinator and perform routing there.
You can see a diagram of how screens can be linked to coordinators.
Cocoapods is used as a dependency manager. Alternatively, you can use an alternative to SPM. Unfortunately, some dependencies still don't support SPM. I would like to dwell separately on the Networking directory. We use Alamofire as a basis.
- EndPointType - constructor protocol for queries
- Networker - class describing basic queries (MultipartData, RequestInterceptor, parsers)
- Requester - directory with request factories for each flow.
Divided into separate factories to avoid massive structures.
- AuthRequester - factory of requests for registration, authorization, forgot password, etc.
- It should be done with each flow separately.
- TokenStorage - service for storing tokens and secure information (KeychainSwift) Models for networking are parsed using Codable and are located in the BusinessLogicLayer / Models directory
The project has three schemes configured for building applications with different keys and input data. Why do you need it? For example, different backups, bundles, application names, as well as various keys and tokens for different services can be used for different environments. All this can be configured through configuration files in the CoreLayer / Configurations directory.
To summarize, the basic rules for scaling the architecture should be highlighted.
- We try to follow the SOLID principles.
- Each service should have its own area of responsibility: for example, the Auth service will be responsible for working specifically with authorization, registration, etc. User service will be responsible specifically for working with user data, no matter if it's networking or a database.
- Each coordinator works only with his own flow, the file size does not exceed 500 lines. Otherwise, we create a SubCoorinator according to the principle of the main coordinator's work with its subcoordinators.
- Following the decomposition, we try not to overload services, presenters and controllers. Where can we break it down into separate entities and services.
- For the privacy of individual classes, we work through protocols.
- Kosyi Vlad, CHI Software
Copyright 2021 CHI Software.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.