import UIKit
protocol Coordinator: AnyObject {
var navigationController: UINavigationController { get set }
var childCoordinators: [Coordinator] { get set }
func start()
}
extension Coordinator {
func addChild(_ coordinator: Coordinator) {
childCoordinators.append(coordinator)
}
func removeChild(_ coordinator: Coordinator) {
childCoordinators = childCoordinators.filter { $0 !== coordinator }
}
}
import UIKit
class AppCoordinator: Coordinator {
var navigationController: UINavigationController
var childCoordinators: [Coordinator] = []
private let window: UIWindow
init(window: UIWindow) {
self.window = window
self.navigationController = UINavigationController()
}
func start() {
// Check if user is logged in
if AuthManager.shared.isLoggedIn {
showMainFlow()
} else {
showAuthFlow()
}
window.rootViewController = navigationController
window.makeKeyAndVisible()
}
private func showAuthFlow() {
let authCoordinator = AuthCoordinator(navigationController: navigationController)
authCoordinator.delegate = self
addChild(authCoordinator)
authCoordinator.start()
}
private func showMainFlow() {
let mainCoordinator = MainCoordinator(navigationController: navigationController)
addChild(mainCoordinator)
mainCoordinator.start()
}
}
extension AppCoordinator: AuthCoordinatorDelegate {
func authCoordinatorDidFinish(_ coordinator: AuthCoordinator) {
removeChild(coordinator)
showMainFlow()
}
}
import UIKit
class PostsCoordinator: Coordinator {
var navigationController: UINavigationController
var childCoordinators: [Coordinator] = []
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func start() {
let viewModel = PostsViewModel()
let viewController = PostsViewController(viewModel: viewModel)
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}
func showPostDetail(postId: Int) {
let viewModel = PostDetailViewModel(postId: postId)
let viewController = PostDetailViewController(viewModel: viewModel)
viewController.coordinator = self
navigationController.pushViewController(viewController, animated: true)
}
func showCreatePost() {
let createCoordinator = CreatePostCoordinator(
navigationController: navigationController
)
createCoordinator.delegate = self
addChild(createCoordinator)
createCoordinator.start()
}
}
protocol CreatePostCoordinatorDelegate: AnyObject {
func createPostCoordinatorDidFinish(_ coordinator: CreatePostCoordinator)
}
extension PostsCoordinator: CreatePostCoordinatorDelegate {
func createPostCoordinatorDidFinish(_ coordinator: CreatePostCoordinator) {
removeChild(coordinator)
}
}
The Coordinator pattern separates navigation logic from view controllers, promoting reusability and testability. Coordinators own navigation controllers and decide which screens to show based on user actions. Each flow (onboarding, main, settings) has its own coordinator. Child coordinators handle sub-flows, notifying parents when complete. This removes navigation code from view controllers, making them focused on presentation. ViewControllers call coordinator methods instead of pushing directly. For SwiftUI, coordinators work with NavigationStack's programmatic navigation. The pattern scales to complex apps with multiple entry points and deep linking.