Home   →   Blog   →   The use and adaptation of the VIPER architecture on our own example of development, part 2

The use and adaptation of the VIPER architecture on our own example of development, part 2

This is the second part of the article about our experience of using and adapting the Viper architecture. In the first part we discussed the basics, now it's time to talk about structuring and creating project skeleton for VIPER.

General Info

To simplify the development process and make it more clear, we usually separate classes into different folders and groups such as Constants, Extensions, Services, Models, Presentation. In addition, Extensions could be divided into smaller groups like UIExtensions, Animations, etc., and Models - into DTO, Business, etc. As for Services, we will discuss them below.

As you can see, there is nothing particularly difficult about these groups, but let's take a closer look at the project structure in terms of VIPER architecture.

1. Services

For the code clarity, services are better to be divided into several groups like Infrastructure and Business. The first group should contain essential services (API service, Settings service, etc), and the second one consists of all services working with data and business logic.

And there is also the main class called Service Assembly that is a shared instance comprising all services in the app e.g. API service, Settings service, business services, etc.

protocol ServicesAssemblyProtocol {

   var application: UIApplication { get }

   var apiService: APIService { get }

   var weatherService: WeatherService { get }


All services are initialized with required instances of other ones. For example, UserService might need access to API or Database services.

class ServicesAssemblyImpl: ServicesAssemblyProtocol {

   let application: UIApplication

   let apiService: APIService

   let weatherService: WeatherService

   init(application: UIApplication) {

       self.application = application

       apiService = APIServiceImpl()

       weatherService = WeatherServiceImpl(apiService: apiService)



All setup logic for services is generally implemented in AppDelegate since we might need it at the very start.

   func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

       // Setup services

       ServicesAssembly.setup(application: application)


       // Setup everything else if needed

       return true


2. Presentation

Presentation is a group with all layout logic inside. Let’s examine its structure in depth.

PresentationAssembly is shared class containing references to the presentation layer.

protocol PresentationAssemblyProtocol {

   var router: AppRouterProtocol! { get }

   var whisper: InAppNotificationsProvider! { get }


class PresentationAssembly: PresentationAssemblyProtocol {

   static let shared = PresentationAssembly()

   var router: AppRouterProtocol!

   var whisper: InAppNotificationsProvider!


   func setup(withNavigation navigation: UINavigationController, modules: Array<ModuleFactoryProtocol>, urlScheme: String, services: ServicesAssemblyProtocol) {

       router = AppRouterImpl(withNavigation: navigation, modules: modules, urlScheme: urlScheme)

       whisper = InAppNotificationsProviderImpl(withNavigation: navigation)




Let’s consider Application root more carefully.

Application root

Application root is an entry point to the app. It is called by AppDelegate and responsible for launching an application and all configuration needed before that moment. 

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {


       // Setup here       

       // Start application

       appRoot = ApplicationRoot(withNavigation: navigationController)



       return true


It sets up every necessary service, router, presentation stuff and chooses a module to show first (login or main screen, for instance). Application root also contains all existing modules inside in order to know about each of them to be able to create it.

class ApplicationRoot: NSObject {

   let modules : Array<ModuleFactoryProtocol> = [




   // MARK:

   fileprivate let router: AppRouterProtocol

   fileprivate let whisper: InAppNotificationsProvider

   init(withNavigation navigation: UINavigationController) {

       let services =  ServicesAssembly.shared

       let presentation = PresentationAssembly.shared

       presentation.setup(withNavigation: navigation, modules: modules, urlScheme: "viper", services: services)

       router = presentation.router

       whisper = presentation.whisper   



   func start() {

       let urn = StartScreenFactory.shared.moduleURN

       router.pushModule(byUrn: urn, animated: true, completion: { (_) in





Application router

AppRouter contains all routing logic. It is created by Application root and responsible for navigation between modules e.g. push/pop or present/dismiss etc.

protocol AppRouterProtocol {

   var navigationController: UINavigationController { get }

   func pushModule(byUrn urn: String, animated: Bool, completion: ModuleCompletionHandler?)    

   func presentModule(byUrn urn: String, animated: Bool, completion: ModuleCompletionHandler?)    

   func popToViewController(_ controller: UIViewController, animated: Bool)

   func dismissCurrentController(animated: Bool)


It’s global in general but can be moved to each module or added to some of them depending on the complexity if we want so.

As you can see Routing group also contains ModuleFactoryProtocol

protocol ModuleFactoryProtocol {


    * Module URN ( ex. profile:{userID} )


   var moduleURN: String { get }    


    * Create module with arguments

    * Returns module root UIViewController, must implement ModuleInputProtocol.


   func createModule(arguments: NamedValuesType, completion: ModuleCompletionHandler?) -> UIViewController


which defines the way how new module can be created and ModuleInputProtocol

protocol ModuleInputProtocol {


    * Configure module with arguments.

    * Calls form Module factory


   func setupInitialState(withArguments args: NamedValuesType, completion: ModuleCompletionHandler?)


defines the way module could be configured with additional parameters.

Presentation group also contains any additional groups required by the app. For example, InAppNotifications (alerts, toast etc), StyleKit (responsible for styling application if necessary), SocialServices (Facebook, Twitter, etc), and lots of other logic your app may need.


Views is created for keeping all the custom layouts which are placed just here. Besides, it can include the following groups inside such as Layouts, Cells, Collections, etc.

User stories

This part consists of all your screens and UI logic and contains every VIPER module that is located here and should include: Factory, Configurator, View, Presenter, and Interactor.

We will describe the module structure in the next article and right now just say that it may have storyboard or xib file inside if needed.

So, to conclude, to simplify finding the specific class or service let’s mention that the structure of the project is extremely clear. In addition, it’s good practice to keep group and folder structure the same way.

In the next - third - part of our article we'll tell you about creating a module in terms of VIPER architecture: units, their responsibilities etc.

Read our blog to know more!

comments powered by Disqus
Cf68cdaaf75f9cd1417267c6b1cafb3813c488a1 Virtual Reality Applications
Augmented reality apps are widely used – from geolocalization to using it in gaming industry. Augmented reality app is a new way to access data determined by environment conditions.
754d17aa02f8c56a0e0b671d45bf2455f6177062 Agile Methodology (Scrum)
Scrum is the very popular agile methodology for managing product development and project delivery. Scrum is the framework that could be applied for the development of product use cases, different projects or entire products.
1a1b621bfd24aba09a56bb25cf18719ad46ef190 News App Development
Smartphones are regularly used everywhere & anytime: in cars, on the way to the office, during the rest on holidays or weekends. That’s very convenient way for users to access important or just fun information with the help of news mobile app.
D63ac21dfd17c4acc93d52d9bdc72fea10e84edd Geolocation Services in Mobile Tracking Software
Geolocation services are used by many mobile apps, websites, mobile operators etc.