Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/AndreyPanov/ApplicationCoordinator

Coordinators Essential tutorial
https://github.com/AndreyPanov/ApplicationCoordinator

application-coordinator architecture coordinators ios protocols swift

Last synced: about 2 months ago
JSON representation

Coordinators Essential tutorial

Lists

README

        

# ApplicationCoordinator
A lot of developers need to change navigation flow frequently, because it depends on business tasks. And they spend a huge amount of time for re-writing code. In this approach, I demonstrate our implementation of Coordinators, the creation of a protocol-oriented, testable architecture written on pure Swift without the downcast and, also to avoid the violation of the S.O.L.I.D. principles.

Based on the post about Application Coordinators [khanlou.com](http://khanlou.com/2015/10/coordinators-redux/) and Application Controller pattern description [martinfowler.com](http://martinfowler.com/eaaCatalog/applicationController.html).

### Coordinators Essential tutorial. Part I [medium.com](https://medium.com/blacklane-engineering/coordinators-essential-tutorial-part-i-376c836e9ba7)

### Coordinators Essential tutorial. Part II [medium.com](https://medium.com/@panovdev/coordinators-essential-tutorial-part-ii-b5ab3eb4a74)

Example provides very basic structure with 6 controllers and 5 coordinators with mock data and logic.
![](/str.jpg)

I used a protocol for coordinators in this example:
```swift
protocol Coordinator: class {
func start()
func start(with option: DeepLinkOption?)
}
```
All flow controllers have a protocols (we need to configure blocks and handle callbacks in coordinators):
```swift
protocol ItemsListView: BaseView {
var authNeed: (() -> ())? { get set }
var onItemSelect: (ItemList -> ())? { get set }
var onCreateButtonTap: (() -> ())? { get set }
}
```
In this example I use factories for creating coordinators and controllers (we can mock them in tests).
```swift
protocol CoordinatorFactory {
func makeItemCoordinator(navController navController: UINavigationController?) -> Coordinator
func makeItemCoordinator() -> Coordinator

func makeItemCreationCoordinatorBox(navController: UINavigationController?) ->
(configurator: Coordinator & ItemCreateCoordinatorOutput,
toPresent: Presentable?)
}
```
The base coordinator stores dependencies of child coordinators
```swift
class BaseCoordinator: Coordinator {

var childCoordinators: [Coordinator] = []

func start() { }
func start(with option: DeepLinkOption?) { }

// add only unique object
func addDependency(_ coordinator: Coordinator) {

for element in childCoordinators {
if element === coordinator { return }
}
childCoordinators.append(coordinator)
}

func removeDependency(_ coordinator: Coordinator?) {
guard
childCoordinators.isEmpty == false,
let coordinator = coordinator
else { return }

for (index, element) in childCoordinators.enumerated() {
if element === coordinator {
childCoordinators.remove(at: index)
break
}
}
}
}
```
AppDelegate store lazy reference for the Application Coordinator
```swift
var rootController: UINavigationController {
return self.window!.rootViewController as! UINavigationController
}

private lazy var applicationCoordinator: Coordinator = self.makeCoordinator()

func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let notification = launchOptions?[.remoteNotification] as? [String: AnyObject]
let deepLink = DeepLinkOption.build(with: notification)
applicationCoordinator.start(with: deepLink)
return true
}

private func makeCoordinator() -> Coordinator {
return ApplicationCoordinator(
router: RouterImp(rootController: self.rootController),
coordinatorFactory: CoordinatorFactoryImp()
)
}
```