Coordinator: iOS naviqasiyası üçün koordinator nümunəsinin əsas anlayışları

Müəllif: IT Sectr Dərc olunub: 2026-02-18 Oxuma vaxtı: 9 dəq

Coordinator (koordinator) — naviqasiyanın arxitektura nümunəsidir, ekranlar arasında keçid məntiqini ViewController-dan ayrı siniflərə çıxarır. Nümunə 2015-ci ildə Soroush Khanlou tərəfindən təklif edilmiş və iOS icmasında geniş yayılmışdır. Coordinator tətbiqin flow-unu idarə edir: ViewController yaradır və göstərir, ekranlar arasında məlumat ötürür və flow-un tamamlanmasını emal edir. Nümunə Massive View Controller problemini həll edir, naviqasiyanı kontrollerdən çıxarır. Ətraflı — Coordinator orijinal məqaləsində.

Əsas məqamlar

  • Coordinator — keçid məntiqini ViewController-dan çıxaran naviqasiya nümunəsi
  • Məsuliyyət bölgüsü — ViewController UI-ni, Coordinator naviqasiyanı idarə edir
  • Router — UINavigationController abstraksiyası üçün Coordinator-un köməkçi komponenti
  • Flow — bir Coordinator tərəfindən idarə olunan ekranlar ardıcıllığı (məsələn, onboarding)
  • Delegasiya — uşaq koordinatorları valideynə delegate/protocol vasitəsilə hesabat verir

Coordinator nədir: naviqasiya nümunəsinin mahiyyəti

Coordinator — iOS tətbiqində naviqasiya üçün məsuliyyəti öz üzərinə götürən nümunədir. Standart UIKit-də ViewController keçidləri özü idarə edir: present, push, show segue — bütün naviqasiya metodları UIViewController-dən çağrılır. Coordinator bu məntiqi çıxarır: ViewController hadisə barədə məlumat verir (məsələn, „istifadəçi daxilolma düyməsini basdı“), Coordinator növbəti hansı ekranı göstərəcəyinə qərar verir. ViewController yalnız UI məntiqi ilə qalır və naviqasiyanı koordinatora həvalə edir.

Nümunənin strukturu — start() və finish() metodları ilə CoordinatorProtocol. start() — flow-un başlanğıcı: ilk ViewController-ün yaradılması və göstərilməsi. finish() — valideyn koordinatora bildirişlə flow-un tamamlanması. Router — UINavigationController (və ya UISplitViewController) üzərində qabıq, show, push, pop, dismiss metodlarını təqdim edir. Koordinator birbaşa UINavigationController ilə işləmir — yalnız Router vasitəsilə. Bu, naviqasiyanı test etməyə və UI freymvorkunu dəyişməyə imkan verir.

KomponentRolNümunə
CoordinatorNaviqasiya flow-unun idarə edilməsiAuthCoordinator, ProfileCoordinator
RouterUINavigationController üzərində abstraksiyapush, present, pop, dismiss
ViewControllerUI + hadisələrin Coordinator-a delegasiyasıLoginViewController.delegate

Coordinator-un həll etdiyi problemlər — Massive View Controller (naviqasiya — kontrollerin böyüməsinin ümumi səbəbi). Standart UIKit-də ViewController prepareForSegue, naviqasiya delegate-ləri, unwind segues emalını ehtiva edir. Coordinator bunu aradan qaldırır. Storyboard-da Segue — ekranlar arasında statik əlaqə, Coordinator şərtlərlə dinamik naviqasiya təmin edir. Naviqasiyanın test edilməsi mümkün olur: Coordinator-u UI olmadan, Router çağırışlarının ardıcıllığını yoxlayaraq test etmək olar.

Swift-də Coordinator: Router və Flow ilə tətbiqi

Swift-də əsas Coordinator — Router üçün əlaqəli tip və start/finish metodları ilə protokol. Router — UINavigationController-i abstraksiya edən protokol. Router-in konkret tətbiqi UINavigationController-i qabıqlayır və metodları ona həvalə edir. Coordinator Router-i init-də qəbul edir və naviqasiya üçün istifadə edir. Uşaq koordinatorları həyat dövrünü idarə etmək üçün childCoordinators massivində saxlanılır.

swift
// Router — naviqasiya abstraksiyası
protocol RouterProtocol: AnyObject {
    func push(_ viewController: UIViewController, animated: Bool)
    func pop(animated: Bool)
    func present(_ viewController: UIViewController, animated: Bool)
    func dismiss(animated: Bool)
}

final class NavigationRouter: RouterProtocol {
    private let navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func push(_ vc: UIViewController, animated: Bool) {
        navigationController.pushViewController(vc, animated: animated)
    }

    func pop(animated: Bool) {
        navigationController.popViewController(animated: animated)
    }

    func present(_ vc: UIViewController, animated: Bool) {
        navigationController.present(vc, animated: animated)
    }

    func dismiss(animated: Bool) {
        navigationController.dismiss(animated: animated)
    }
}

// Coordinator — flow-un idarə edilməsi
protocol CoordinatorProtocol: AnyObject {
    var childCoordinators: [CoordinatorProtocol] { get set }
    var router: RouterProtocol { get }
    func start()
    func finish()
}

class AuthCoordinator: CoordinatorProtocol {
    var childCoordinators: [CoordinatorProtocol] = []
    let router: RouterProtocol

    init(router: RouterProtocol) {
        self.router = router
    }

    func start() {
        let loginVC = LoginViewController()
        loginVC.onLogin = { [weak self] in
            self?.showHome()
        }
        router.push(loginVC, animated: true)
    }

    private func showHome() {
        let homeCoordinator = HomeCoordinator(router: router)
        childCoordinators.append(homeCoordinator)
        homeCoordinator.start()
    }

    func finish() {
        childCoordinators.removeAll()
        router.pop(animated: true)
    }
}

AppDelegate/SceneDelegate-də Coordinator-un yaradılması — AppDelegate və ya SceneDelegate UINavigationController yaradır, onu NavigationRouter-ə qabıqlayır, kök Coordinator (AppCoordinator) yaradır və start() çağırır. AppCoordinator tətbiqin vəziyyətindən asılı olaraq onboarding, daxilolma və ya əsas ekranı göstərməyə qərar verir. Coordinator — naviqasiya üçün yeganə giriş nöqtəsi, ViewController digər ekranlar haqqında bilmir.

Uşaq Coordinator və koordinatorlar iyerarxiyası

Koordinatorlar iyerarxiyası — AppCoordinator → AuthCoordinator/MainCoordinator → ProfileCoordinator/SettingsCoordinator. Uşaq koordinator valideyn tərəfindən yaradılır və childCoordinators massivində saxlanılır. Uşaq koordinator işini bitirdikdə, valideyndə finish() çağırır və valideyn onu childCoordinators-dan silir. Bu, yaddaş sızmalarının qarşısını alır: Coordinator ViewController-a (Router vasitəsilə) güclü istinada malikdir və childCoordinators-dan silinmədən obyekt azad olunmayacaq.

swift
// Coordinator -> Parent əlaqəsi üçün Delegate
protocol AuthCoordinatorDelegate: AnyObject {
    func authCoordinatorFinished(_ coordinator: AuthCoordinator)
}

class AuthCoordinator: CoordinatorProtocol {
    weak var delegate: AuthCoordinatorDelegate?

    func finish() {
        delegate?.authCoordinatorFinished(self)
    }
}

// AppCoordinator — valideyn
class AppCoordinator: AuthCoordinatorDelegate {
    func startAuthFlow() {
        let authCoordinator = AuthCoordinator(router: router)
        authCoordinator.delegate = self
        childCoordinators.append(authCoordinator)
        authCoordinator.start()
    }

    func authCoordinatorFinished(_ coordinator: AuthCoordinator) {
        childCoordinators.removeAll { $0 is AuthCoordinator }
        startMainFlow()
    }
}

childCoordinators-un idarə edilməsi — Coordinator-un massivdən silinməsi onu azad etməyin yeganə yoludur. Tamamlanmış Coordinator-u silməyi unutsanız, o, ViewController-larla birlikdə yaddaşda qalır. Tövsiyə olunur: valideynin didMove(toParent:), tamamlanma callback-i və ya avtomatik silmə üçün Combine publisher. Coordinator nümunəsi bildiriş mexanizmini spesifikasiya etmir — delegate, closure və ya Combine — seçim tərtibatçınındır.

Koordinatorlar arasında məlumat ötürmə üsulları

Delegate vasitəsilə məlumat ötürülməsi — uşaq Coordinator nəticələrin ötürüldüyü metodlarla delegate protokolunu təyin edir: func authCoordinator(_:didLoginWith user: User). Valideyn protokolu tətbiq edir və uşaq flow-un tamamlanmasında məlumat alır. Bu tip təhlükəsiz və aşkardır. Çatışmazlıq: hər uşaq Coordinator üçün ayrıca protokol yazmaq lazımdır. 10+ Coordinator olan layihələr üçün bu, faylların sayının artmasına səbəb olur.

Result tipi vasitəsilə məlumat ötürülməsi — finish metodu Result qəbul edir, burada Output flow nəticəsinin ümumi tipidir. Coordinator — nəticənin əlaqəli tipi ilə generik. Callback ilə start(): start(completion: @escaping (Output) -> Void). Bu, kodu qısaldır: hər koordinator üçün ayrıca protokol yazmağa ehtiyac yoxdur. RxSwift/Combine: Coordinator nəticəni PassthroughSubject/Publisher vasitəsilə dərc edir. Seçim komandanın arxitektura yanaşmasından asılıdır.

MetodÜstünlüklərÇatışmazlıqlar
DelegateTip təhlükəsiz, aşkar, ayrı protokollarÇox protokol, çox boilerplate
ClosureKompakt, az faylRetain cycle-i debug etmək çətindir
Combine/RxReaktiv, asan birləşdirməkKitabxanadan asılılıq, çətin Debug

Shared data layer — Coordinatory birbaşa məlumat ötürmür, ortaq xidmət/repozitoridən istifadə edir. AuthCoordinator token-i Keychain/UserDefaults-da saxlayır, ProfileCoordinator oradan oxuyur. Coordinatory ortaq vəziyyət (Dependency Injection container) vasitəsilə ünsiyyət qurur, birbaşa çağırışlarla deyil. Bu, Coordinatorların bağlılığını azaldır, lakin ortaq vəziyyətdən gizli asılılıqlar yaradır.

Coordinator-un Router, VIPER və MVVM-C ilə müqayisəsi

Coordinator vs Router — Router UINavigationController-i abstraksiya edən Coordinator komponentidir. Coordinator flow-a cavabdehdir (hansı ekranı göstərmək), Router — mexanikaya (necə göstərmək: push/present). Router „necə“, Coordinator „nə“dir. Router-i Coordinator olmadan istifadə etmək olar (məsələn, Navigator-sinqleton), lakin Coordinator Router olmadan — sadəcə fərqli abstraksiya ilə ViewController. Adətən hər iki nümunə birlikdə istifadə olunur.

Coordinator vs VIPER — VIPER naviqasiya üçün Coordinator-un analoqu olan Wireframe komponentinə malikdir. VIPER-də Wireframe modulun bir hissəsidir, Coordinator — modullar üzərində ayrıca təbəqə. VIPER modulu (View-Interactor-Presenter-Entity-Router) naviqasiyanı modulun bir hissəsi kimi daxil edir. Coordinator modullara nisbətən xarici: modulları yaradır və birləşdirir, lakin onların tərkibinə daxil deyil. Coordinator ekranların müxtəlif flow-larda təkrar istifadəsi üçün daha çevikdir.

MVVM-C — MVVM-nin Coordinator ilə genişləndirilməsi. ViewModel birbaşa Coordinator-u tanımır — ViewController naviqasiyanı ViewModel vasitəsilə həvalə edir, ViewModel protokol vasitəsilə koordinatoru çağırır. MVVM-C — SwiftUI ilə iOS layihələri üçün standart yanaşma: Coordinator NavigationStack və ya fullScreenCover-i idarə edir, ViewModel vəziyyəti dərc edərək koordinatoru çağırır. Apple SwiftUI üçün Coordinator-u tövsiyə etmir — NavigationStack və NavigationPath daxili naviqasiya mexanizmləridir.

swift
// MVVM-C: ViewModel protokol vasitəsilə Coordinator-u çağırır
protocol AuthNavigationProtocol: AnyObject {
    func showMainScreen()
    func showForgotPassword()
}

class AuthViewModel: ObservableObject {
    weak var navigation: AuthNavigationProtocol?

    func loginTapped() {
        // məntiq...
        navigation?.showMainScreen()
    }
}

Tez-tez verilən suallar

SwiftUI üçün Coordinator lazımdırmı?

SwiftUI üçün daxili naviqasiya (NavigationStack, NavigationPath) tez-tez Coordinator-u əvəz edir. Apple path-based naviqasiyanı tövsiyə edir. Coordinator dərin şərtləri olan mürəkkəb flow-lar üçün məna kəsb edir (roldan asılı olaraq onboarding-daxilolma-əsas ekran). Sadə SwiftUI tətbiqləri üçün Coordinator artıqdır — NavigationPath istifadə edin.

Coordinator Router-dirmi?

Xeyr, bunlar fərqli nümunələrdir. Coordinator naviqasiya flow-unu idarə edir: hansı ekranı göstərəcəyinə qərar verir, ViewController yaradır və onları birləşdirir. Router — UINavigationController üzərində abstraksiya: push, present, pop, dismiss. Coordinator naviqasiyanı yerinə yetirmək üçün Router-dən istifadə edir. Bəzi tətbiqlərdə Router Coordinator məntiqini ehtiva edir (Router-per-screen), lakin bu orijinal nümunədən sapmadır.

Coordinator-da retain cycle-dən necə qaçınmaq olar?

İki əsas sızma yeri: childCoordinators (valideyn uşağı saxlayır, silməyi unudur) və Router (UINavigationController ViewController-i saxlayır). Həlli: həmişə uşaq Coordinator-u finish() zamanı massivdən silmək. Delegate üçün weak istinaddan istifadə edin. Router üçün — UINavigationController-a güclü istinad saxlamayın, əgər o artıq window iyerarxiyasındadırsa. Coordinator-un deinit-ini test edin.

Coordinator nə vaxt artıqdır?

3-5 ekranlı tətbiqlər üçün Coordinator artıqdır — segue və ya sadə navigationController.pushViewController daha sadədir. NavigationStack ilə SwiftUI tətbiqləri üçün də artıqdır. Coordinator 15+ ekranlı, mürəkkəb flow-lu (şaxələnmiş onboarding, parol bərpası ilə autorizasiya) və qarışıq UIKit/SwiftUI layihələri üçün əsaslandırılmışdır.

Coordinator-u necə test etmək olar?

Mock Router — hansı metodların hansı parametrlərlə çağrıldığını yoxlamaq. childCoordinators-un yoxlanması: start() sonra massiv boş deyil, finish() sonra — boş. Coordinator UI olmadan test edilir: Router protokoldur, onun mock-u UIKit tələb etmir. Async flow üçün XCTestExpectation istifadə edin. Android-də analoji — NavigationController və NavHost-un mock-naviqasiya ilə test edilməsi.

Nəticə

  • Coordinator — keçidləri ViewController-dan ayrı sinfə çıxaran naviqasiya nümunəsi
  • Router — Coordinator tərəfindən istifadə olunan UINavigationController abstraksiyası
  • İyerarxiya — valideyn və uşaq Coordinator nəticələrin delegasiyası ilə
  • MVVM-C — UIKit layihələri üçün Coordinator ilə standart yanaşma
  • SwiftUI — NavigationStack vasitəsilə daxili naviqasiya Coordinator-u əvəz edir
  • Test etmə — Coordinator UIKit olmadan mock Router vasitəsilə test edilir

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun