Coordinator (कोऑर्डिनेटर) — एक आर्किटेक्चरल नेविगेशन पैटर्न है जो स्क्रीन के बीच ट्रांज़िशन के तर्क को ViewController से अलग क्लासेज़ में स्थानांतरित करता है। यह पैटर्न Soroush Khanlou द्वारा 2015 में प्रस्तावित किया गया था और iOS समुदाय में व्यापक रूप से अपनाया गया। Coordinator एप्लिकेशन के flow का प्रबंधन करता है: ViewController बनाता और प्रदर्शित करता है, स्क्रीन के बीच डेटा स्थानांतरित करता है, और flow के पूरा होने को संभालता है। यह पैटर्न कंट्रोलर से नेविगेशन को बाहर निकालकर Massive View Controller समस्या को हल करता है। अधिक जानकारी के लिए Coordinator पर मूल लेख देखें।
मुख्य बिंदु
Coordinator — एक पैटर्न है जो iOS एप्लिकेशन में नेविगेशन की जिम्मेदारी लेता है। मानक UIKit में, ViewController स्वयं ट्रांज़िशन प्रबंधित करता है: present, push, show segue — सभी नेविगेशन विधियाँ UIViewController से कॉल की जाती हैं। Coordinator इस तर्क को बाहर निकालता है: ViewController एक घटना की रिपोर्ट करता है (जैसे, «उपयोगकर्ता ने लॉगिन बटन दबाया»), Coordinator तय करता है कि आगे कौन सी स्क्रीन दिखानी है। ViewController केवल UI तर्क के साथ रहता है और नेविगेशन को कोऑर्डिनेटर को सौंपता है।
पैटर्न संरचना — CoordinatorProtocol जिसमें start() और finish() विधियाँ हैं। start() — flow की शुरुआत: पहला ViewController बनाना और प्रदर्शित करना। finish() — पैरेंट कोऑर्डिनेटर को सूचना के साथ flow का समापन। Router — UINavigationController (या UISplitViewController) के ऊपर एक आवरण, जो show, push, pop, dismiss विधियाँ प्रदान करता है। कोऑर्डिनेटर सीधे UINavigationController के साथ काम नहीं करता — केवल Router के माध्यम से। यह नेविगेशन का परीक्षण करने और UI फ्रेमवर्क बदलने की अनुमति देता है।
| घटक | भूमिका | उदाहरण |
|---|---|---|
| Coordinator | नेविगेशन flow प्रबंधन | AuthCoordinator, ProfileCoordinator |
| Router | UINavigationController पर अमूर्तता | push, present, pop, dismiss |
| ViewController | UI + Coordinator को घटनाओं का प्रत्यायोजन | LoginViewController.delegate |
Coordinator द्वारा हल की जाने वाली समस्याएँ — Massive View Controller (नेविगेशन कंट्रोलर के बढ़ने का एक सामान्य कारण है)। मानक UIKit में, ViewController में prepareForSegue, नेविगेशन delegates, unwind segues की हैंडलिंग होती है। Coordinator इसे समाप्त करता है। Storyboard में Segues स्क्रीन के बीच स्थिर कनेक्शन हैं, Coordinator शर्तों के साथ गतिशील नेविगेशन प्रदान करता है। नेविगेशन का परीक्षण संभव हो जाता है: बिना UI के Coordinator का परीक्षण Router कॉल के अनुक्रम की जाँच करके किया जा सकता है।
Swift में मूल Coordinator — Router के लिए एक संबद्ध प्रकार और start/finish विधियों वाला एक प्रोटोकॉल। Router — UINavigationController को अमूर्त करने वाला प्रोटोकॉल। Router का ठोस कार्यान्वयन UINavigationController को आवरण करता है और उसे विधियाँ सौंपता है। Coordinator init में Router स्वीकार करता है और नेविगेशन के लिए इसका उपयोग करता है। चाइल्ड कोऑर्डिनेटर जीवनचक्र प्रबंधन के लिए childCoordinators सरणी में संग्रहीत किए जाते हैं।
// Router — नेविगेशन अमूर्तता
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 प्रबंधन
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 में Coordinator बनाना — AppDelegate या SceneDelegate UINavigationController बनाता है, इसे NavigationRouter में आवरण करता है, एक रूट Coordinator (AppCoordinator) बनाता है और start() कॉल करता है। AppCoordinator तय करता है कि एप्लिकेशन की स्थिति के आधार पर onboarding, लॉगिन या मुख्य स्क्रीन दिखानी है या नहीं। Coordinator नेविगेशन के लिए एकमात्र प्रवेश बिंदु है, ViewController अन्य स्क्रीन के बारे में नहीं जानता।
कोऑर्डिनेटर पदानुक्रम — AppCoordinator → AuthCoordinator/MainCoordinator → ProfileCoordinator/SettingsCoordinator। चाइल्ड कोऑर्डिनेटर पैरेंट द्वारा बनाया जाता है और childCoordinators सरणी में संग्रहीत किया जाता है। जब चाइल्ड कोऑर्डिनेटर अपना काम पूरा करता है, तो वह पैरेंट पर finish() कॉल करता है, और पैरेंट इसे childCoordinators से हटा देता है। यह मेमोरी लीक को रोकता है: Coordinator के पास ViewController पर एक मजबूत संदर्भ होता है (Router के माध्यम से), और childCoordinators से हटाए बिना ऑब्जेक्ट मुक्त नहीं होगा।
// Coordinator -> Parent संचार के लिए Delegate
protocol AuthCoordinatorDelegate: AnyObject {
func authCoordinatorFinished(_ coordinator: AuthCoordinator)
}
class AuthCoordinator: CoordinatorProtocol {
weak var delegate: AuthCoordinatorDelegate?
func finish() {
delegate?.authCoordinatorFinished(self)
}
}
// AppCoordinator — पैरेंट
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 का प्रबंधन — Coordinator को सरणी से निकालना इसे मुक्त करने का एकमात्र तरीका है। यदि आप पूर्ण हुए Coordinator को हटाना भूल जाते हैं, तो यह अपने ViewControllers सहित मेमोरी में रहता है। अनुशंसित तरीके: पैरेंट का didMove(toParent:), समाप्ति पर callback, या स्वचालित हटाने के लिए Combine publisher। Coordinator पैटर्न सूचना तंत्र निर्दिष्ट नहीं करता — delegate, closure या Combine — चुनाव डेवलपर पर निर्भर है।
delegate के माध्यम से डेटा स्थानांतरण — चाइल्ड Coordinator एक delegate प्रोटोकॉल को परिभाषित करता है जिसमें विधियाँ होती हैं जिनके माध्यम से परिणाम पारित किए जाते हैं: func authCoordinator(_:didLoginWith user: User)। पैरेंट प्रोटोकॉल को लागू करता है और चाइल्ड flow पूरा होने पर डेटा प्राप्त करता है। यह टाइप-सेफ और स्पष्ट है। कमी: प्रत्येक चाइल्ड Coordinator के लिए एक अलग प्रोटोकॉल लिखना आवश्यक है। 10+ Coordinator वाली परियोजनाओं के लिए यह फ़ाइलों में वृद्धि की ओर ले जाता है।
Result प्रकार के माध्यम से डेटा स्थानांतरण — finish विधि Result
| विधि | लाभ | कमियाँ |
|---|---|---|
| Delegate | टाइप-सेफ, स्पष्ट, अलग प्रोटोकॉल | कई प्रोटोकॉल, बहुत अधिक बॉयलरप्लेट |
| Closure | कॉम्पैक्ट, कम फ़ाइलें | retain cycle को डीबग करना कठिन |
| Combine/Rx | रिएक्टिव, संयोजित करना आसान | लाइब्रेरी पर निर्भरता, डीबग करना कठिन |
साझा डेटा परत — Coordinator सीधे डेटा स्थानांतरित नहीं करते, बल्कि एक साझा सेवा/रिपॉजिटरी का उपयोग करते हैं। AuthCoordinator टोकन को Keychain/UserDefaults में सहेजता है, ProfileCoordinator वहाँ से पढ़ता है। Coordinator प्रत्यक्ष कॉल के बजाय साझा स्थिति (Dependency Injection कंटेनर) के माध्यम से संवाद करते हैं। यह Coordinator के बीच युग्मन को कम करता है, लेकिन साझा स्थिति पर अंतर्निहित निर्भरताएँ बनाता है।
Coordinator बनाम Router — Router Coordinator का एक घटक है जो UINavigationController को अमूर्त करता है। Coordinator flow के लिए जिम्मेदार है (कौन सी स्क्रीन दिखानी है), Router — यांत्रिकी के लिए (कैसे दिखाना है: push/present)। Router «कैसे» है, Coordinator «क्या» है। आप Router का उपयोग Coordinator के बिना कर सकते हैं (जैसे, Navigator सिंगलटन), लेकिन Coordinator बिना Router के केवल एक अलग अमूर्तता वाला ViewController है। आमतौर पर दोनों पैटर्न एक साथ उपयोग किए जाते हैं।
Coordinator बनाम VIPER — VIPER में नेविगेशन के लिए जिम्मेदार Wireframe घटक है — Coordinator के अनुरूप। VIPER में, Wireframe मॉड्यूल का हिस्सा है, Coordinator मॉड्यूल के ऊपर एक अलग परत है। VIPER मॉड्यूल (View-Interactor-Presenter-Entity-Router) नेविगेशन को मॉड्यूल के हिस्से के रूप में शामिल करता है। Coordinator मॉड्यूल के लिए बाहरी है: वह मॉड्यूल बनाता और जोड़ता है, लेकिन उनका हिस्सा नहीं है। Coordinator विभिन्न flow में स्क्रीन के पुन: उपयोग के लिए अधिक लचीला है।
MVVM-C — Coordinator के साथ MVVM का विस्तार। ViewModel सीधे Coordinator के बारे में नहीं जानता — ViewController ViewModel के माध्यम से नेविगेशन सौंपता है, ViewModel एक प्रोटोकॉल के माध्यम से coordinator को कॉल करता है। MVVM-C SwiftUI के साथ iOS परियोजनाओं के लिए मानक दृष्टिकोण है: Coordinator NavigationStack या fullScreenCover प्रबंधित करता है, ViewModel स्थिति प्रकाशित करके coordinator को कॉल करता है। Apple SwiftUI के लिए Coordinator की अनुशंसा नहीं करता — NavigationStack और NavigationPath अंतर्निहित नेविगेशन तंत्र हैं।
// MVVM-C: ViewModel प्रोटोकॉल के माध्यम से Coordinator को कॉल करता है
protocol AuthNavigationProtocol: AnyObject {
func showMainScreen()
func showForgotPassword()
}
class AuthViewModel: ObservableObject {
weak var navigation: AuthNavigationProtocol?
func loginTapped() {
// तर्क...
navigation?.showMainScreen()
}
}
अक्सर पूछे जाने वाले प्रश्न
SwiftUI के लिए, अंतर्निहित नेविगेशन (NavigationStack, NavigationPath) अक्सर Coordinator को बदल देता है। Apple path-based नेविगेशन की अनुशंसा करता है। Coordinator जटिल flow के लिए उपयुक्त है जिसमें गहरी शर्तें हों (भूमिका के आधार पर onboarding-लॉगिन-मुख्य स्क्रीन)। सरल SwiftUI अनुप्रयोगों के लिए Coordinator अनावश्यक है — NavigationPath का उपयोग करें।
नहीं, ये अलग पैटर्न हैं। Coordinator नेविगेशन flow का प्रबंधन करता है: तय करता है कि कौन सी स्क्रीन दिखानी है, ViewControllers बनाता और जोड़ता है। Router UINavigationController पर एक अमूर्तता है: push, present, pop, dismiss। Coordinator नेविगेशन निष्पादित करने के लिए Router का उपयोग करता है। कुछ कार्यान्वयनों में Router Coordinator तर्क शामिल करता है (Router-per-screen), लेकिन यह मूल पैटर्न से विचलन है।
दो मुख्य लीक स्रोत: childCoordinators (पैरेंट चाइल्ड को रखता है, हटाना भूल जाता है) और Router (UINavigationController ViewController को रखता है)। समाधान: finish() पर चाइल्ड Coordinator को हमेशा सरणी से हटाएँ। delegate के लिए weak संदर्भ का उपयोग करें। Router के लिए — UINavigationController पर मजबूत संदर्भ न रखें यदि वह पहले से window पदानुक्रम में है। Coordinator के deinit का परीक्षण करें।
3-5 स्क्रीन वाले अनुप्रयोगों के लिए Coordinator अनावश्यक है — segue या सरल navigationController.pushViewController आसान है। NavigationStack के साथ SwiftUI अनुप्रयोगों के लिए भी अनावश्यक है। Coordinator 15+ स्क्रीन, जटिल flow (शाखाओं के साथ onboarding, पासवर्ड पुनर्प्राप्ति के साथ प्राधिकरण) और मिश्रित UIKit/SwiftUI परियोजनाओं के लिए उचित है।
Mock Router — जाँचें कि कौन सी विधियाँ और किन मापदंडों के साथ कॉल की गईं। childCoordinators की जाँच करें: start() के बाद सरणी खाली नहीं है, finish() के बाद — खाली। Coordinator बिना UI के परीक्षण किया जाता है: Router एक प्रोटोकॉल है, इसके mock को UIKit की आवश्यकता नहीं है। async flow के लिए XCTestExpectation का उपयोग करें। Android में — mock नेविगेशन के साथ NavigationController और NavHost का समान परीक्षण।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें