VIPER: asosiy tushunchalar, View-Interactor-Presenter-Entity-Router namunasi

Muallif: IT Sectr Nashr etilgan: 2026-02-16 O'qish vaqti: 9 daq

VIPER (View-Interactor-Presenter-Entity-Router) — Mutual Mobile kompaniyasi tomonidan iOS ilovalari uchun ishlab chiqilgan modul arxitekturasi. VIPER ilovani besh qatlamga ajratadi: View ko'rsatish uchun, Interactor — biznes mantiqi uchun, Presenter — ma'lumotlarni tayyorlash uchun, Entity — ma'lumot modellari uchun, Router — modullar orasidagi navigatsiya uchun javob beradi. VIPER mobil arxitekturalar orasida yagona javobgarlik tamoyilining eng batafsil amalga oshirilishidir. Batafsil — objc.io saytidagi maqolada.

Asosiy fikrlar

  • VIPER — besh komponent: View, Interactor, Presenter, Entity, Router aniq javobgarlik chegaralari bilan
  • Modullik — har bir ekran (modul) izolyatsiya qilingan, protokollar orqali aloqa
  • Router — navigatsiyani Presenter dan chiqaradi, iOS navigatsiya muammosini hal qiladi
  • Interactor — biznes mantiqini o'z ichiga oladi va UIKit ga bog'liq emas, unit-testlar bilan tekshiriladi
  • iOS-native — VIPER SwiftUI paydo bo'lishidan oldin UIKit uchun yaratilgan va yirik iOS loyihalari uchun standart bo'lib qolmoqda

VIPER nima: modul arxitekturasining besh komponenti

VIPER (View-Interactor-Presenter-Entity-Router) — 2013–2014 yillarda Mutual Mobile kompaniyasi tomonidan yirik iOS loyihalari uchun ishlab chiqilgan arxitektura namunasi. Ilovaning har bir ekrani qat'iy belgilangan vazifalarga ega besh komponentdan iborat alohida moduldir. VIPER mobil ishlab chiqishda yagona javobgarlik tamoyilining (Single Responsibility Principle) eng qat'iy amalga oshirilishidir: hech bir komponent boshqasi qila oladigan ishni bajarmaydi.

View — faqat Presenter tomonidan uzatilgan ma'lumotlarni ko'rsatish uchun javobgar bo'lgan passiv komponent. View biznes mantiqini o'z ichiga olmaydi, navigatsiyani boshqarmaydi, tarmoq so'rovlarini yubormaydi. iOS da — ViewProtocol protokoli bilan UIViewController. Interactor — Entity va xizmatlar (tarmoq, ma'lumotlar bazasi, GPS) bilan ishlaydigan biznes mantiqi qatlami. Interactor UIKit ni import qilmaydi. Presenter — View va Interactor o'rtasidagi vositachi: Interactor dan ma'lumotlarni oladi, ko'rsatish uchun formatlaydi, View ga uzatadi. Presenter ham UIKit ni import qilmaydi. Entity — ma'lumot modellari (struct, class). Router — navigatsiyani boshqaradi: modullarni yaratadi, ekranlarni ochadi, modullar orasida ma'lumotlarni uzatadi.

KomponentJavobgarlikBog'liqliklar
ViewKo'rsatish, animatsiyalar, imo-ishoralarUIKit (faqat View)
InteractorBiznes mantiqi, tarmoq, ma'lumotlar bazasiEntity, xizmatlar
PresenterMa'lumotlarni formatlash, View buyruqlariViewProtocol, Interactor
EntityMa'lumot modellariYo'q
RouterNavigatsiya, modullarni yaratishUIViewController (o'tishlar uchun)

Komponentlar orasidagi aloqalar protokollar orqali tavsiflanadi. ViewProtocol ko'rsatish metodlarini, InteractorProtocol — biznes mantiqi metodlarini, PresenterProtocol — hodisalarni qayta ishlash metodlarini, RouterProtocol — navigatsiya metodlarini belgilaydi. Har bir komponent boshqasi bilan faqat protokol orqali muloqot qiladi, bu esa amalga oshirishlarni oson almashtirish va izolyatsiya qilingan test qilish imkonini beradi. Bitta ekranli VIPER moduli o'rtacha 5 protokol + 5 sinf + 1 Builder/Assembler = ekran uchun 11 faylni o'z ichiga oladi.

Swift da VIPER: modul, Router va Presenter

VIPER modulini qurish Builder (yoki Assembler) tomonidan amalga oshiriladi, u barcha besh komponentni yaratadi va ularni protokollar orqali bog'laydi. Builder — komponentlar bir-birining aniq turlarini biladigan yagona joy. Qurilishdan so'ng View ko'rsatish uchun tashqariga qaytariladi, qolgan zanjir toza va izolyatsiya qilingan holda test qilinadi.

swift
// Protokol — View
protocol UserViewProtocol: AnyObject {
    func display(name: String)
    func display(email: String)
    func showLoading()
    func hideLoading()
}

// Protokol — Interactor
protocol UserInteractorProtocol {
    func fetchUser(id: Int, completion: @escaping (Result<User, Error>) -> Void)
}

// Protokol — Router
protocol UserRouterProtocol {
    func navigateToProfile(userId: Int)
}

// Interactor — biznes mantiqi
final class UserInteractor: UserInteractorProtocol {
    private let service: UserService

    init(service: UserService) { self.service = service }

    func fetchUser(id: Int, completion: @escaping (Result<User, Error>) -> Void) {
        service.fetchUser(id: id, completion: completion)
    }
}

// Presenter — ma'lumotlarni tayyorlash
final class UserPresenter {
    private weak var view: UserViewProtocol?
    private let interactor: UserInteractorProtocol
    private let router: UserRouterProtocol

    init(interactor: UserInteractorProtocol, router: UserRouterProtocol) {
        self.interactor = interactor
        self.router = router
    }

    func setView(_ view: UserViewProtocol) {
        self.view = view
    }

    func viewDidLoad() {
        view?.showLoading()
        interactor.fetchUser(id: 42) { [weak self] result in
            guard let self else { return }
            self.view?.hideLoading()
            switch result {
            case .success(let user):
                self.view?.display(name: user.name)
                self.view?.display(email: user.email)
            case .failure(let error):
                // xatoni qayta ishlash
            }
        }
    }
}

// Router — navigatsiya
final class UserRouter: UserRouterProtocol {
    private weak var viewController: UIViewController?

    func setViewController(_ vc: UIViewController) {
        viewController = vc
    }

    func navigateToProfile(userId: Int) {
        let profileModule = ProfileModuleBuilder.build(userId: userId)
        viewController?.navigationController?.pushViewController(profileModule, animated: true)
    }
}

// Builder — modulni qurish
enum UserModuleBuilder {
    static func build(userId: Int) -> UIViewController {
        let service = UserService()
        let interactor = UserInteractor(service: service)
        let router = UserRouter()
        let presenter = UserPresenter(interactor: interactor, router: router)
        let viewController = UserViewController(presenter: presenter)
        presenter.setView(viewController)
        router.setViewController(viewController)
        return viewController
    }
}

Builder/Assembler — bog'liqliklarni qo'lda kiritishni (Dependency Injection) amalga oshiruvchi VIPER ning asosiy elementi. Konstruktor orqali bog'liqliklarni kiritish (constructor injection) komponentning o'z bog'liqliklarisiz yaratilmasligini kafolatlaydi. Zamonaviy VIPER da Builder Swinject (DI konteyner) dan foydalanishi mumkin, ammo qo'lda qurish test uchun shaffofroq qoladi. IT Sectr da biz murakkab mantiqli modullar uchun qo'lda qurish bilan VIPER ni qo'llaymiz — bu yangi dasturchilar uchun kodni o'qishni osonlashtiradi.

Mapper (Formatter) — VIPER ning ixtiyoriy oltinchi komponenti. Mapper Entity (ma'lumotlar bazasi/server modellari) ni ViewModel (ko'rsatish modellari) ga aylantiradi. Entity id, first_name, last_name, email maydonlari bilan UserDTO ni o'z ichiga oladi. ViewModel — name (first_name + last_name) va email bilan UserDisplayItem. Mapper Presenter da bajariladi. Ma'lumotlarni xaritalash murakkab bo'lsa (bir nechta Entity → bitta ViewModel), Mapper test qilish uchun alohida sinfga chiqariladi.

VIPER modullari orasidagi aloqa

VIPER modullari izolyatsiya qilingan va bir-biri haqida bilmaydi. Modullar orasidagi aloqa Router orqali amalga oshiriladi. Foydalanuvchi foydalanuvchi ekranidagi „Profil" tugmasini bosganda, Presenter router.navigateToProfile(userId: 42) ni chaqiradi. Router ProfileModuleBuilder.build(userId: 42) orqali yangi modul yaratadi va uni navigationController.push orqali ochadi. Ma'lumot oqimi: Modul A → Router A → Modul B Builder → Modul B yaratiladi va ochiladi.

Ma'lumotlarni orqaga uzatish (masalan, tanlash ekranida shahar tanlandi → profilni tahrirlash ekraniga qaytarildi) VIPER da delegatlar yoki yopilishlar (closure) orqali amalga oshiriladi. Modul B didSelectCity(_ city: City) metodi bilan ModuleBDelegate protokolini belgilaydi. Modul A ushbu protokolni amalga oshiradi. Router A delegatni Module B Builder ga uzatadi. Shahar tanlanganda Modul B delegate?.didSelectCity(city) ni chaqiradi. Bu har bir UIKit dasturchisiga tanish bo'lgan standart iOS amaliyotidir.

SsenariyMexanizmMisol
Oldinga o'tishRouter → BuildernavigateToProfile(userId:)
Ma'lumotni orqaga uzatishDelegatedidSelectCity(_:)
Tizim bildirishnomasiNotificationCenterUserDidLogout
Interactor dan hodisaPresenter → ViewWebSocket message

NotificationCenter bir vaqtning o'zida bir nechta modulga ta'sir qiladigan tizim hodisalari (chiqish, tarif o'zgarishi, push bildirishnomalari) uchun ishlatiladi. Router yoki AppDelegate Notification ga obuna bo'ladi, kerakli modulni yaratadi yoki holatni yangilaydi. VIPER NotificationCenter ni taqiqlamaydi — muhimi, u faqat 1-to-many hodisalari uchun ishlatilishi, 1-to-1 aloqa uchun esa delegatlar yoki yopilishlar qo'llanilishi kerak.

VIPER ni MVVM va Clean Architecture bilan solishtirish

VIPER vs MVVM — VIPER ekran uchun 2–3 barobar ko'p kod talab qiladi, lekin komponentlarning mutlaq izolyatsiyasini ta'minlaydi. ViewModel + SwiftUI bilan MVVM sodda va tezroq, ammo 5+ dasturchidan iborat jamoalarda yomonroq masshtablanadi. VIPER kim nima uchun javobgar ekanligini qat'iy belgilaydi: Interactor — faqat biznes mantiqi, Presenter — formatlash, Router — navigatsiya. MVVM da ViewModel ko'pincha kattalashib, navigatsiya va biznes mantiqini o'ziga oladi.

VIPER vs Clean Architecture — VIPER iOS UIKit uchun moslashtirilgan Clean Architecture ning alohida holatidir. Interactor = Use Case, Entity = Domain Model, Presenter = Presentation, Router = Controller Robert Martin terminlarida. Clean Architecture Interactor va ma'lumotlar o'rtasida Gateway/Repository qatlamini qo'shadi, bu VIPER da odatda ajratilmaydi. SwiftUI dagi zamonaviy loyihalar uchun aksariyat jamoalar Clean Architecture (The Composable Architecture) yoki MVVM ni tanlab, VIPER ni UIKit dagi eski kod uchun qoldiradi.

VIPER ni qachon tanlash kerak — 5 dasturchidan iborat jamoalar, 50 ekrandan UIKit loyihasi, test talablari 80% dan yuqori, faqat iOS (VIPER qayta yozilmasdan Android ga o'tkazilmaydi). VIPER bashorat qilinadigan strukturani ta'minlaydi: yangi dasturchi modulni 15 daqiqada tushunadi. Biroq ishlab chiqish tezligi ko'proq fayllar soni sababli MVVM bilan solishtirganda 20–30% past. IT Sectr da biz 3 kishidan iborat jamoalar bilan UIKit dagi enterprise loyihalari uchun VIPER dan foydalanamiz va SwiftUI dagi yangi loyihalar uchun Clean Architecture ni afzal ko'ramiz.

VIPER modullarini test qilish

VIPER test uchun mo'ljallangan — har bir komponent protokollar orqali izolyatsiya qilingan holda test qilinadi. Interactor mock-xizmatlar bilan test qilinadi: fetchUser ning to'g'ri ID bilan chaqirilgani va natijaning Presenter ga uzatilgani tekshiriladi. Presenter mock View va Interactor obyektlari bilan test qilinadi. Router mock-navigatsiya bilan test qilinadi: navigateToProfile ning to'g'ri userId bilan chaqirilgani va to'g'ri modul yaratilgani tekshiriladi. View UI testlari (XCUITest) bilan test qilinadi.

swift
import XCTest

final class UserPresenterTests: XCTestCase {
    func testViewDidLoad_callsFetchUserAndUpdatesView() {
        // Given
        let view = MockUserView()
        let interactor = MockUserInteractor()
        let router = MockUserRouter()
        let presenter = UserPresenter(interactor: interactor, router: router)
        presenter.setView(view)
        let expectedUser = User(id: 42, name: "John", email: "john@test.com")
        interactor.result = .success(expectedUser)

        // When
        presenter.viewDidLoad()

        // Then
        XCTAssertEqual(interactor.capturedUserId, 42)
        XCTAssertEqual(view.displayedName, "John")
        XCTAssertTrue(view.didShowLoading)
    }
}

Mock-obyektlar VIPER uchun qo'lda (saqlanadigan capture xususiyatlariga ega sinf) yoki Cuckoo / Mockingbird kutubxonalari orqali yaratiladi. Qo'lda mock sinflari sodda va tushunarliroq, ayniqsa yangi dasturchilarni o'rgatish uchun. Har bir mock captured qiymatlarni (capturedUserId, displayedName) va chaqiruv bayroqlarini (didShowLoading) saqlaydi. Test oxirida metod nafaqat chaqirilganligi, balki qanday parametrlar bilan chaqirilganligi ham tekshiriladi — bu ma'lumot oqimining to'g'riligiga ishonch beradi.

Kod qamrovi IT Sectr ning VIPER loyihalarida Interactor uchun 85–95%, Presenter uchun 90–95%, Router uchun 70–80%, View uchun 30–50% (UI testlari orqali) ga etadi. View skrinshot testlari (SnapshotTesting, 1,5K yulduz) bilan test qilinadi — bu XCUITest dan tezroq va ko'proq holatlarni qamrab oladi. VIPER loyihasining umumiy qamrovi odatda 70–80% ni tashkil qiladi, bu MVVM loyihasidan (50–65%) yuqori, ammo test yozish uchun ko'proq vaqt talab etadi (rivojlanish vaqtining 30–40% i MVVM dagi 20–25% ga nisbatan).

Tez-tez so'raladigan savollar

Bitta VIPER modulida nechta fayl bor?

Kamida 11 fayl: 5 protokol (ViewProtocol, InteractorProtocol, PresenterProtocol, RouterProtocol, Entity), 5 amalga oshirish (ViewController, Interactor, Presenter, Router, Entity) va Builder/Assembler. Mapper (Formatter) bilan — 12–13. 50 ekranli loyiha uchun bu faqat VIPER modullari uchun 550–650 fayl. MVVM ekran uchun 3 fayl talab qiladi (ViewModel, View, Model) — 50 ekran uchun 150 fayl.

Android da VIPER dan foydalanish mumkinmi?

Ha, nazariy jihatdan VIPER Android ga o'tkazilishi mumkin, ammo amalda qo'llanilmaydi — Google Jetpack bilan MVVM ni tavsiya qiladi. VIPER iOS UIKit uchun yaratilgan, bu yerda ViewController hayotiy tsikli tufayli test qilish qiyin. Android da Jetpack ViewModel VIPER izolyatsiyasisiz test muammosini hal qiladi. VIPER ning Android analogi — module/feature ga bo'lingan Clean Architecture.

VIPER va Clean Architecture o'rtasidagi farq nima?

VIPER iOS ga xos Clean Architecture amalga oshirilishidir. Interactor Use Case ga, Entity — Domain Model ga, Presenter — Presentation qatlamiga mos keladi. Clean Architecture Interactor va ma'lumotlar o'rtasida Repository/Gateway qo'shadi, bu VIPER da odatda Interactor ichida amalga oshiriladi. Clean Architecture Router ni belgilamaydi — navigatsiya amalga oshirish ixtiyoriga qoldiriladi.

SwiftUI loyihalari uchun VIPER kerakmi?

Yo'q — SwiftUI MVVM + Combine uchun mo'ljallangan. SwiftUI da VIPER ortiqcha: deklarativ UI bilan bitta ekran uchun besh komponent foydasiz yuk. SwiftUI uchun MVVM yoki TCA (The Composable Architecture) ni tanlang. VIPER UIKit eski kodi va iOS 12 va undan past minimal versiyali loyihalar uchun dolzarbligicha qolmoqda.

VIPER modullari orasida ma'lumotlarni qanday uzatish mumkin?

Router orqali. Modul A router.navigateToProfile(userId: id) ni chaqiradi. Router A Builder orqali modul B ni yaratadi, userId ni uzatadi. Orqaga uzatish — delegat orqali: modul B ModuleBDelegate protokolini belgilaydi, modul A uni amalga oshiradi va Router orqali uzatadi. Tizim hodisalari (chiqish) — NotificationCenter orqali.

Xulosa

  • VIPER — qat'iy bo'linish bilan besh komponent: View, Interactor, Presenter, Entity, Router
  • Modullik — har bir ekran izolyatsiya qilingan, Builder constructor injection orqali bog'liqliklarni yig'adi
  • Router — navigatsiyani Presenter dan chiqaradi, iOS da navigatsiya muammosini hal qiladi
  • Interactor — UIKit siz toza biznes mantiqi, unit-testlar bilan tekshiriladi
  • Kod miqdori — ekran uchun 11+ fayl, ishlab chiqish MVVM dan 20–30% sekinroq
  • Test — 70–80% qamrov, Interactor va Presenter mock-obyektlar orqali test qilinadi
  • SwiftUI vs UIKit — VIPER UIKit uchun (eski kod), MVVM/TCA SwiftUI uchun

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing