Explain Coordinator Pattern
Explain Coordinator Pattern
:::info[TL/DR]
The Coordinator Pattern centralizes navigation logic in iOS applications, organizing flow logic between view controllers by separating that
responsibility into a dedicated coordinator object.
:::
Concept Overview
The Coordinator Pattern is a structural design pattern that manages the flow between view controllers, decoupling the navigation logic from
individual view controllers. The key components of this pattern are:
1. Coordinator Protocol: Defines the methods that all coordinators must implement.
2. Concrete Coordinator: Implements the coordinator protocol and manages specific flows.
4. Concrete Router: Implements the router protocol, handling actual navigation actions.
5. View Controllers: Delegates navigation logic to the coordinator, keeping their logic focused on UI concerns.
Playground Example
Here is the complete example from the book that demonstrates the How to Code flow using the Coordinator Pattern:
import UIKit
extension Router {
public func present(_ viewController: UIViewController, animated: Bool) {
present(viewController, animated: animated, onDismissed: nil)
}
}
// Concrete Router
public class NavigationRouter: NSObject, Router, UINavigationControllerDelegate {
private let navigationController: UINavigationController
public func present(_ viewController: UIViewController, animated: Bool, onDismissed: (() -> Void)?) {
navigationController.pushViewController(viewController, animated: animated)
}
// MARK: - StepViewController
public class StepViewController: UIViewController {
var delegate: StepViewControllerDelegate?
var buttonColor: UIColor?
var stepText: String?
var stepTitle: String?
static func instantiate(delegate: StepViewControllerDelegate, buttonColor: UIColor, text: String, title: String) ->
StepViewController {
let viewController = StepViewController()
viewController.delegate = delegate
viewController.buttonColor = buttonColor
viewController.stepText = text
viewController.stepTitle = title
return viewController
}
// Example usage
let navigationController = UINavigationController()
let router = NavigationRouter(navigationController: navigationController)
let coordinator = HowToCodeCoordinator(router: router)
coordinator.start()
PlaygroundPage.current.liveView = navigationController
How It Works:
Coordinator: The HowToCodeCoordinator manages the sequence of view controllers and handles navigation between steps.
Router: The NavigationRouter is responsible for presenting and dismissing the view controllers.
View Controllers: Each StepViewController displays content and delegates the "next" action back to the coordinator.
When to Use
Managing complex navigation: If your app has multiple view controllers with complex navigation flows.
Decoupling navigation: When you want to keep navigation logic separate from view controllers to improve modularity and testability.
When to Be Careful
1. Overuse in Simple Apps: If your app is simple with minimal navigation, using the Coordinator Pattern may introduce unnecessary
complexity. In these cases, sticking to view controller-based navigation can be more efficient.
2. Memory Management: Coordinators that manage a large number of children or view controllers must be careful with memory
management, particularly in terms of retaining view controllers or child coordinators for too long. Use weak references to avoid memory
leaks.
3. Handling Deep Links: When implementing deep linking, the coordinator must be able to navigate to specific screens based on external
inputs. This can make the flow logic more complex, requiring additional work to manage and handle multiple potential entry points into
the flow.
4. Maintaining State Across Coordinators: Managing application state when using multiple coordinators can become difficult. You need
to decide how to share state between coordinators and ensure that state is managed appropriately across flows without adding too
much interdependence between them.
5. Testing: Although the Coordinator Pattern makes the navigation logic more modular, testing flows becomes more complex as the
number of coordinators grows. Coordinators often need to be mocked or stubbed in order to fully test the logic.
:::tip[In Bullets]
Be cautious of overusing it in small apps and handling memory and deep linking carefully.
:::