iOS app architecture we use.
MVPCF = Model View Presenter Coordinator Factory;
It is similar to the combination of Reactive MVP + Coordinator + Factory. Presenter is the same thing as ViewModel in MVVM but it has a different name. ViewModel name is used for a different approach;
SOLID principles are the core of our architecture.
For our architecture, we created a pretty simple and small library RCKit aka Reactive Clean Kit, that contains everything we need for building an app using this architecture.
1. For assembling project we use DI pattern with Swinject library.
App has shared Container where we register all shared dependencies we need to use across the whole app.
Every flow has its own folder. Every flow has its "manager" called Coordinator. Every flow has its own DI Container that contains specific dependencies for the flow.
This object is responsible for handling navigation through the application, handling push notifications, and other routing actions.
Coordinator uses one container viewcontroller like UINavigationController or UISplitViewController.
Coordinator builds the screens (Modules) and controls the flow.
The only exception is a main ApplicationCoordinator that accepts UIWindow instead of container ViewController.
3. Every Module for example has the following structure:
Abstraction for creation anything. Factory is very important part of this architecture, because it injects dependencies. BaseFactory contains Container we use to inject dependencies that we need. Factory can be used for Modules as well as building Cells, NSOperations, etc where we need to inject something. We can inject factories where we need and it gives us a lot of flexibility!
protocol<Name>Factory {func make()-><Name>Routes
}Abstraction for Routes of the Module. ViewController implements this protocol. Closures fire in Coordinator and Coordinator performs what is needed.
protocol<Name>Routes:ModuleRoutes{varcanceled:(()->Void)!{getset}varfinished:((String)->Void)!{getset}}Abstraction for Presenter. It has default implementation. It contains a logic of the presentation. It has the bindings for input and output. Presenter contains structures called ViewModel as well as plain types, ready to use in View.
// for example
struct<SomeCell>ViewModel {letname:StringletdateFormatter:String}protocol<Name>Presenter {varsearchInput:BehaviorRelay<String?>{get}varsearchResults:BehaviorRelay<[<SomeCell>ViewModel]>{get}varnextButtonAvailable:BehaviorRelay<Bool>{get}}Abstraction for view. It has default implementation inherited from UIView.
It contains custom view for ViewController.
protocol<Name>View:ViewContainer{varaddButton:UIButton{get}vartextField:UITextField{get}}Inherired from UIViewController Implements Routes protocol.
It is responsible for:
- binding Presenter to View;
- registering for events as a button tap;
- firing Routes closures. Basically it is the main building structure of screens.
classDefault<Name>Presenter:<Name>Presenter{letname:BehaviorRelay<String?>=BehaviorRelay(value:nil)letaddButtonAvailable:BehaviorRelay<Bool>=BehaviorRelay(value:false)privatevarcreating=BehaviorRelay(value:false)privatevardisposable:Disposable?privateletdisposeBag=DisposeBag()privateletmodelManager:ModelManagerprivateletreachabilityManager:ReachabilityManager
// injecting via initializer
init(modelManager:ModelManager, reachabilityManager:ReachabilityManager){self.modelManager = modelManager
self.reachabilityManager = reachabilityManager
}}Every dependency should have only one responsibility!
For example:
protocolReachabilityManager{varconnectionIsReachable:BehaviorRelay<Bool>{get}}Or this:
protocolFirstLaunchManager{func performTasksOnFirstLaunch()}Or this:
protocolLogoutManager{func logout()}MVVM and MVP. MVPCF uses MVVM and MVP as a base architecture and improves both with coordinators and factories;
VIPER. It has a Presenter as the main Object of the module. Router is not Obvious. MVPCF has ViewController as the main object of the module and Coordinator that handles the navigation. Also, standard VIPER is not reactive from the box.
RIBs. Interactor in RIBs is the main object of module, but MVPCF has ViewController as the main object. Our approach is more obvious for typical developers.