Open b099l3 opened 3 years ago
After doing some reading I quite like the approach taken in these articles by Andrey Panov: https://medium.com/blacklane-engineering/coordinators-essential-tutorial-part-i-376c836e9ba7 https://medium.com/blacklane-engineering/coordinators-essential-tutorial-part-ii-b5ab3eb4a74
He also describes this pattern in a way that it could be used in MVVM, MVC, VIPER, etc, by calling the VM, VC, IPV - "modules"
Sample code here, it also has tests 🤘: https://github.com/AndreyPanov/ApplicationCoordinator
Why should we use it?
The main goal is to have unchained module-to-module responsibility and to build modules completely independently from each other. After this iteration, we can easily reuse them in different flows.
He uses a similar protocol to the one mentioned above but simpler:
protocol Coordinator: class {
func start()
func start(with option: DeepLinkOption?) // This is used for deep linking
}
He has extracted the UINavigationController
out of the coordinator and into an object called Router (similar to the RayWenderlich approach and others). I like this idea as it has serves the single responsibility principle, and I can see things getting messy if not extracted out.
He has also moved the childCoordinators
into a baseCoordinator
so that
So this example's coordinator is composed of two protocols, Coordinator & CoordinatorOutput, to allow for optional results after a flow has finished.
protocol CoordinatorOutput {
var finishFlow: (Item -> Void)? { get set }
}
using "show" prefix in coordinator methods when moving to another module, e.g.,
func showItemList()
using "run" prefix in coordinator methods when moving to another flow/coordinator, e.g.,
func runCreationFlow()
The architecture elements proposed here are:
I feel this approach has a lot of fo flexibility and looks easy to extend for other cases in navigation flow. I am going to start with this approach and feedback and issues.
Pavle Pesic has blogged about using this pattern How to implement flow coordinator pattern and has some sample code
protocol Coordinator {
var navigationcontroller: UINavigationController? { get set }
funceventOccurred(with type: Event)
func start()
}
protocol Coordinating {
var coordinator: Coordinator? { get set }
}
enum Event {
case buttonTapped
}
Coordinating
protocol to allow Viewcontrollers
to have a reference to their coordinators, others have used delegates or other methods for the comms between VC and coordinators.SceneDelegate
easySet of tutorials on creaditing MVVM architecture with Coordinator
protocol Coordinator {
var childCoordinators: [Coordinator] { get }
func start()
}
rootViewcontroller
init's with window - init(window:)
init(navigationController:)
SceneDelegate
public protocol Coordinator: class {
var children: [Coordinator] { get set }
var router: Router { get }
func present(animated: Bool, onDismissed: (() -> Void)?)
func dismiss(animated: Bool)
func presentChild(_ child: Coordinator,
animated: Bool,
onDismissed: (() -> Void)?)
}
Use this pattern to decouple view controllers from one another. The only component that knows about view controllers directly is the coordinator.
Consequently, view controllers are much more reusable: If you want to create a new flow within your app, you simply create a new coordinator!
AppDelegateRouter
for setting up the window and rootviewcontroller
Topic: Coordinator Pattern
Coordinator pattern created by Soroush Khanlou from a series of articles and a talk given at NSSpain
Example protocol for the most basic Coordinator:
This is a good starting point for the protocol but not every project uses this protocol. I will need to assess other example protocols to see why they have changed parts of this.
Why:
This pattern is to:
Here is a simple example,
with the coordinator pattern and delegation this can result in:
This is a much cleaner approach as we can reuse the
HomeViewController
in other places within our app or swap out its coordinator to change the navigation inhomeViewControllerDidPressButton
Notes:
This pattern has been around since 2015 so a lot has progressed since then, prepare to find it has evolved.
Some seem to use Delegates for events between Coordinator and ViewControllers others use Closures, need to see why this is the case?
Using closures with the coordinator pattern
Possibly use both?
Why do some of the examples use Factories?
Resources:
Articles:
https://www.raywenderlich.com/books/design-patterns-by-tutorials/v3.0/chapters/23-coordinator-pattern https://medium.com/blacklane-engineering/coordinators-essential-tutorial-part-i-376c836e9ba7 https://medium.com/blacklane-engineering/coordinators-essential-tutorial-part-ii-b5ab3eb4a74 https://pavlepesic.medium.com/flow-coordination-pattern-5eb60cd220d5 - references Andrey's Coordinator and others
https://www.hackingwithswift.com/articles/71/how-to-use-the-coordinator-pattern-in-ios-apps https://wojciechkulik.pl/ios/mvvm-coordinators-rxswift-and-sample-ios-application-with-authentication https://mattwyskiel.com/posts/2016/07/20/protocol-oriented-app-coordinator-swift.html
https://medium.com/devexperts/real-world-example-of-using-coordinator-pattern-in-an-ios-app-d13df10496a5
https://benoitpasquier.com/coordinator-pattern-navigation-back-button-swift/
Videos:
Examples:
https://github.com/AndreyPanov/ApplicationCoordinator
https://github.com/daveneff/Coordinator https://github.com/igorkulman/iOSSampleApp https://github.com/wojciech-kulik/Swift-MVVMC-Demo
https://github.com/hanifsgy/Journal-MVVMCRxSwift https://github.com/behrad-kzm/SpotifyExplorer https://github.com/omerfarukozturk/MovieBox-iOS-MVVMC https://github.com/sunshinejr/Kittygram
SwiftUI https://github.com/rundfunk47/stinsen https://github.com/SwiftUIX/Coordinator