ALCoodinator
This repository contains a library implementing the Coordinator pattern, which is a design pattern used in iOS app development to manage app navigation flows. The library provides a set of classes and protocols that can be used to implement the Coordinator pattern in an iOS app. It works either UIKit or SwiftUI apps
Its core navigation has created with UINavigationController (UIKit) with the aim to get profit about navigation stack.
Getting Started
To use the Coordinator pattern library in your iOS project, you’ll need to add the library files to your project and set up a Coordinator object. Here are the basic steps:
- Create a SceneDelegate class if your app supports scenes:
import UIKit
import ALCoordinator
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var mainCoordinator: Coordinator
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.makeKeyAndVisible()
setupCoordinator(window: window, animated: true)
}
private func setupCoordinator(window: UIWindow?, animated: Bool = false) {
mainCoordinator = .init()
window?.rootViewController = mainCoordinator.root
mainCoordinator?.start(animated: animated)
BaseCoordinator.mainCoordinator = mainCoordinator
}
}
- In your app’s AppDelegate file, set the SceneDelegate class as the windowScene delegate:
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {}
// Add this method
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let sceneDelegate = SceneDelegate()
sceneDelegate.scene(windowScene, willConnectTo: session, options: connectionOptions)
}
}
- Create class MainCoordinator:
class MainCoordinator: BaseCoordinator {
init() {
super.init(parent: nil)
}
override func start(animated: Bool = false) {
let coordinator = OnboardingCoordinator(withParent: self)
coordinator.start(animated: animated)
}
}
- Create custom coordinator:
-
SwiftUI:
class OnboardingCoordinator: CoordinatorSUI<OnboardingRouter> { override func start(animated: Bool) { show(.firstStep) parent.startChildCoordinator(self, animated: animated) } func showStep2() { show(.secondStep) } func showLoginCoordinator() { let coordinator = LoginCoordinator() coordinator.start() } } enum OnboardingRouter: NavigationRouter { case firstStep case secondStep // MARK: NavigationRouter var transition: NavigationTranisitionStyle { switch self { case .firstStep, secondStep: return .push } } func view() -> any View { switch self { case .firstStep: return FirstStepView() case .secondStep: return SecondStepView() } } }
-
UIKit:
class OnboardingCoordinator: BaseCoordinator { override func start(animated: Bool) { let vc = FirstViewController() root.viewControllers.append(vc) parent.startChildCoordinator(self, animated: animated) } func showStep2() { let vc = SecondViewController() push(vc) } func showLoginCoordinator() { let coordinator = LoginCoordinator() coordinator.start() } }
How build Tabbar?
-
Create a router
enum HomeRouter: CaseIterable, TabbarPage { case marketplace case settings // MARK: NavigationRouter func coordinator(parent: Coordinator) -> Coordinator { switch self { case .settings: return SettingCoordinator(parent: parent) case .marketplace: return MarketplaceCoordinator(parent: parent) } } // MARK: TabbarPageDataSource public var title: String { switch self { case .marketplace: return "Marketplace" case .settings: return "Settings" } } public var icon: String { switch self { case .marketplace: return "house" case .settings: return "gearshape" } } public var position: Int { switch self { case .marketplace: return 0 case .settings: return 1 } } }
-
Create a TabbarCoordinator
-
Default tabbar build with UIKIT (It also works with SwiftUI)
class HomeCoordinator: TabbarCoordinatorSUI<HomeRouter> { public init(withParent parent: Coordinator) { let pages: [Router] = [.marketplace, .settings] super.init(withParent: parent, pages: pages) } }
-
Custom view (SwiftUI)
class HomeCoordinator: TabbarCoordinatorSUI<HomeRouter> { public init(withParent parent: Coordinator) { let pages: [Router] = [.marketplace, .settings] let view = HomeTabbarView(pages: pages) super.init(withParent: parent, pages: pages, customView: .custom(value: view)) view.$currentPage .sink { [weak self] page in self?.tabController.selectedIndex = page.position }.store(in: &cancelables) } }
Actions:
Actions you can perform from the coordinator depends on the kind of coordinator used. For instance, using a BaseCoordinator, CoordinatorSUI or Coordinator some of the functions you can perform are:
Name | Description |
---|---|
root |
variable to get navigation controller. |
start() |
Starts the navigation flow managed by the coordinator. This method should be called to begin a navigation flow. Params: animated: Bool default true |
finish() |
Finishes the navigation flow managed by the coordinator. This method should be called to end a navigation flow. Params: completion: (() -> Void)?, default nil animated: Bool, default true |
push(_:) |
Pushes a view controller onto the receiver’s stack and updates the display (only for UIKit). Params: viewController: UIViewController animated: Bool, default true |
present(_:) |
Presents a view controller modally (only for UIKit). Params: viewController: UIViewController animated: Bool, default true completion: (() -> Void)?, default nil |
pop(_:) |
Pops the top view controller from the navigation stack and updates the display . Params: animated: Bool, default true |
popToRoot(_:) |
Pops all the view controllers on the stack except the root view controller and updates the display. Params: animated: Bool, default true |
popToView(_:) |
Pops view controllers until the specified view controller is at the top of the navigation stack. if the view is onto navigation stack returns true. e.i: popToView(MyObject.self, animated: false). Params: view: Any animated: Bool, default true |
dismiss(_:) |
Dismisses the view controller that was presented modally by the view controller. Params: completion: (() -> Void)?, default nil animated: Bool, default true |
close(_:) |
If a view controller is presented as modal, it calls the dismiss(:) > function; otherwise, pop(:) .
Params:
completion: (() -> Void)?, default nil
animated: Bool, default true
|
topCoordinator(_:) |
Returns the last coordinator presented |
restart(_:) |
Finish all its children and finally call start() function.
Paramss
completion: (() -> Void)?, default nil
animated: Bool, default true
|
startChildCoordinator(_:) |
It is a faster way to initialize a secondary coordinator. Inserting a child to its child coordinators and finally it calls present(:) function.
Paramss
coordinator: Coordinator, child coordinator
animated: Bool, default true
|
Classes
In addition to the functions listed above, the Coordinator-pattern library provides several classes that can be used to simplify the implementation of the Coordinator pattern in an iOS app. These classes are:
BaseCoordinator
The BaseCoordinator class provides a basic implementation of the Coordinator protocol, with default implementations. This class can be subclassed to create custom coordinator objects that implement the Coordinator protocol.
TabbarCoordinatorSUI
The TabbarCoordinatorSUI class is a specialized coordinator object that is designed to manage the navigation flow of a tab bar interface. This class provides methods for adding child coordinators for each tab in the tab bar, and for managing the selection of tabs.
CoordinatorSUI
The CoordinatorSUI class is a specialized coordinator object that is designed to manage the navigation flow of a SwiftUI app. This class provides methods for showing views.
TabbarPage
The typealias TabbarPage is a short way to implement protocols TabbarPageDataSource & TabbarNavigationRouter
Installation ?
SPM
Open Xcode and your project, click File / Swift Packages / Add package dependency… . In the textfield “Enter package repository URL”, write https://github.com/felilo/AFCoordinator/ and press Next twice
Contributing
Contributions to the ALCoordinator library are welcome! To contribute, simply fork this repository and make your changes in a new branch. When your changes are ready, submit a pull request to this repository for review.
License
The ALCoordinator library is released under the MIT license. See the LICENSE file for more information.