The Coordinator pattern helps organize navigation in an app. It keeps screens and navigation logic separate for easier management.
Coordinator pattern in iOS Swift
protocol Coordinator {
var childCoordinators: [Coordinator] { get set }
var navigationController: UINavigationController { get set }
func start()
}The Coordinator protocol defines a basic structure for coordinators.
The start() method begins the navigation flow.
class MainCoordinator: Coordinator {
var childCoordinators = [Coordinator]()
var navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func start() {
let vc = ViewController()
vc.coordinator = self
navigationController.pushViewController(vc, animated: true)
}
}func showDetail() {
let detailCoordinator = DetailCoordinator(navigationController: navigationController)
childCoordinators.append(detailCoordinator)
detailCoordinator.start()
}This app uses the Coordinator pattern to manage navigation. The MainCoordinator starts with a home screen that has a button. When tapped, it navigates to a detail screen.
import UIKit protocol Coordinator { var childCoordinators: [Coordinator] { get set } var navigationController: UINavigationController { get set } func start() } class MainCoordinator: Coordinator { var childCoordinators = [Coordinator]() var navigationController: UINavigationController init(navigationController: UINavigationController) { self.navigationController = navigationController } func start() { let vc = ViewController() vc.coordinator = self navigationController.pushViewController(vc, animated: true) } func showDetail() { let detailVC = DetailViewController() navigationController.pushViewController(detailVC, animated: true) } } class ViewController: UIViewController { weak var coordinator: MainCoordinator? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white title = "Home" let button = UIButton(type: .system) button.setTitle("Go to Detail", for: .normal) button.addTarget(self, action: #selector(goToDetail), for: .touchUpInside) button.frame = CGRect(x: 100, y: 200, width: 150, height: 50) view.addSubview(button) } @objc func goToDetail() { coordinator?.showDetail() } } class DetailViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .lightGray title = "Detail" } } @main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var coordinator: MainCoordinator? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let navController = UINavigationController() coordinator = MainCoordinator(navigationController: navController) coordinator?.start() window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = navController window?.makeKeyAndVisible() return true } }
Keep coordinators focused on navigation only, not UI details.
Use child coordinators to handle complex flows inside your app.
Make sure to keep references to child coordinators to avoid them being deallocated too soon.
The Coordinator pattern separates navigation from view controllers.
It makes your app easier to manage and test.
Use coordinators to start and control screen flows.
Practice
Coordinator pattern in iOS development?Solution
Step 1: Understand the role of Coordinator
The Coordinator pattern is designed to manage navigation and screen flow in an app.Step 2: Compare with other options
Data persistence, network requests, and UI styling are handled by other parts of the app, not the Coordinator.Final Answer:
To separate navigation logic from view controllers -> Option AQuick Check:
Coordinator = navigation separation [OK]
- Confusing Coordinator with data managers
- Thinking Coordinator styles UI
- Assuming Coordinator handles network calls
Solution
Step 1: Identify protocol syntax
In Swift, protocols are declared with theprotocolkeyword and define method signatures without implementation.Step 2: Check each option
protocol Coordinator { func start() } correctly declares a protocol with astart()method signature. class Coordinator { func start() {} } is a class, not a protocol. struct Coordinator { var start: () -> Void } is a struct with a closure property, not a protocol. enum Coordinator { case start } is an enum, which is not used for protocols.Final Answer:
protocol Coordinator { func start() } -> Option AQuick Check:
Protocol syntax = protocol Coordinator { func start() } [OK]
- Using class instead of protocol
- Adding method implementation in protocol
- Confusing struct or enum with protocol
appCoordinator.start() is called?
protocol Coordinator {
func start()
}
class AppCoordinator: Coordinator {
func start() {
print("App started")
}
}
let appCoordinator = AppCoordinator()
appCoordinator.start()Solution
Step 1: Analyze the class and method
TheAppCoordinatorclass implements thestart()method which prints "App started".Step 2: Check method call
CallingappCoordinator.start()executes the print statement insidestart().Final Answer:
App started -> Option DQuick Check:
Method call prints message [OK]
- Assuming start() is missing
- Thinking code won't compile
- Expecting no output
protocol Coordinator {
func start()
}
class MainCoordinator: Coordinator {
func start() {
print("Starting main flow")
}
func startFlow() {
print("Flow started")
}
}Solution
Step 1: Check protocol conformance
TheMainCoordinatorclass implements the requiredstart()method from theCoordinatorprotocol.Step 2: Verify additional methods
Having extra methods likestartFlow()is allowed and does not cause errors.Final Answer:
No error, code is correct -> Option BQuick Check:
Extra methods allowed, required methods implemented [OK]
- Thinking extra methods must be in protocol
- Assuming missing methods cause errors
- Confusing protocol with class requirements
MainCoordinator and then show the home screen after login. Which approach best uses the Coordinator pattern to handle this navigation?Solution
Step 1: Understand Coordinator responsibilities
MainCoordinator should manage the overall flow and delegate specific flows to child coordinators like LoginCoordinator.Step 2: Evaluate navigation flow
MainCoordinator creates LoginCoordinator to handle login, then listens for completion to start HomeCoordinator, keeping navigation logic centralized.Step 3: Compare other options
The other options break separation of concerns or do not coordinate flows properly.Final Answer:
MainCoordinator creates and starts a LoginCoordinator, then listens for login completion to start HomeCoordinator -> Option CQuick Check:
Parent coordinator manages child flows [OK]
- Handling navigation only in view controllers
- Child coordinators acting independently
- Mixing multiple screens in one view controller
Ready to prove it?
Pass the test and this pattern moves unknown
