VIPER Architecture Setup for iOS App

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
VIPER Architecture Setup for iOS App
Complex
~3-5 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

VIPER Architecture Setup for iOS App

VIPER — most detailed of iOS architectures. View, Interactor, Presenter, Entity, Router — five components per screen. In small teams this meets skepticism: many files, many protocols, much code. In teams of 5+ working on one UIKit application, VIPER becomes competitive advantage: isolated modules don't conflict in git, Interactor tests without UI, Router encapsulates navigation.

VIPER module anatomy

One screen = one VIPER module. For profile screen:

ProfileModule/
    ProfileView.swift          // UIViewController, implements ProfileViewProtocol
    ProfilePresenter.swift     // presentation logic, implements ProfilePresenterProtocol
    ProfileInteractor.swift    // business logic and data work
    ProfileRouter.swift        // navigation, implements ProfileRouterProtocol
    ProfileAssembly.swift      // factory, assembles module and injects dependencies
    Protocols/
        ProfileProtocols.swift // all module protocols in one file

Protocols — VIPER foundation:

// View ← Presenter
protocol ProfileViewProtocol: AnyObject {
    func displayUser(_ viewModel: ProfileViewModel)
    func displayError(_ message: String)
    func setLoading(_ loading: Bool)
}

// Presenter ← View
protocol ProfileViewToPresenterProtocol: AnyObject {
    func viewDidLoad()
    func editButtonTapped()
    func settingsTapped()
}

// Presenter ← Interactor
protocol ProfileInteractorOutputProtocol: AnyObject {
    func didFetchUser(_ user: User)
    func didFailFetchUser(_ error: Error)
}

// Interactor ← Presenter
protocol ProfileInteractorInputProtocol: AnyObject {
    func fetchUser()
}

// Router ← Presenter
protocol ProfileRouterProtocol: AnyObject {
    func navigateToEditProfile(user: User)
    func navigateToSettings()
}

This much code. That's why VIPER uses Xcode templates or generators (Generamba, Vipergen) — one template, generate profile command creates all 7 files with base code.

Interactor — business logic heart

Interactor — only place where business logic lives. Doesn't know UIKit, doesn't know specific storage:

final class ProfileInteractor {
    weak var presenter: ProfileInteractorOutputProtocol?
    private let userRepository: UserRepositoryProtocol

    init(userRepository: UserRepositoryProtocol) {
        self.userRepository = userRepository
    }
}

extension ProfileInteractor: ProfileInteractorInputProtocol {
    func fetchUser() {
        Task {
            do {
                let user = try await userRepository.fetchCurrentUser()
                await MainActor.run {
                    presenter?.didFetchUser(user)
                }
            } catch {
                await MainActor.run {
                    presenter?.didFailFetchUser(error)
                }
            }
        }
    }
}

Testing Interactor: mock UserRepositoryProtocol — clean Swift, XCTest without simulator. This why boilerplate cost justified.

Presenter: data transformation

Presenter receives domain Entity from Interactor and creates ViewModel for View:

extension ProfilePresenter: ProfileInteractorOutputProtocol {
    func didFetchUser(_ user: User) {
        let viewModel = ProfileViewModel(
            displayName: "\(user.firstName) \(user.lastName)",
            avatarURL: user.avatarURL,
            memberSince: DateFormatter.mediumStyle.string(from: user.createdAt),
            isVerified: user.verificationStatus == .verified
        )
        view?.displayUser(viewModel)
        view?.setLoading(false)
    }
}

ProfileViewModel — struct with UI data, not domain User. View gets ready strings, doesn't format.

Assembly: module assembly

All initialization and DI — in Assembly:

enum ProfileAssembly {
    static func build(coordinator: AppCoordinator) -> UIViewController {
        let interactor = ProfileInteractor(
            userRepository: DI.resolve(UserRepositoryProtocol.self)
        )
        let router = ProfileRouter(coordinator: coordinator)
        let presenter = ProfilePresenter(interactor: interactor, router: router)
        let view = ProfileViewController()

        view.presenter = presenter
        presenter.view = view
        interactor.presenter = presenter

        return view
    }
}

Entire module dependency graph visible in one file. Adding new dependency — only Assembly changes, rest isolated.

Code generators

Writing VIPER manually — too time-expensive. Tools:

  • Generamba — Ruby gem, templates via YAML, Xcode integration with generamba gen ProfileModule viper
  • XcodeGen with custom templates
  • Swift Package with Makefile — own generator based on Stencil templates

On projects with 30+ modules without generator VIPER becomes pain.

VIPER vs Clean Architecture + MVVM

VIPER organic for UIKit + Objective-C legacy or big teams with established processes. For new SwiftUI projects Clean Architecture + MVVM + @Observable — cleaner without boilerplate. For Flutter — BLoC with Clean Architecture closer to VIPER by ideology, but without UIKit dependencies.

VIPER choice justified if:

  • Existing project already on VIPER (refactoring pointless)
  • Team 5+ iOS developers, active parallel code
  • High testability requirements per layer

What we set up

Design protocols → create Xcode template or configure Generamba → implement base VIPER module with tests as example → document team rules → optionally migrate priority MVC/MVP screens.

Work takes 3–5 days for new project including generator and docs. Cost calculated after analyzing module count and team composition.