{"id":758,"url":"https://github.com/AndreyPanov/ApplicationCoordinator","last_synced_at":"2025-07-30T19:32:08.545Z","repository":{"id":53821857,"uuid":"52225988","full_name":"AndreyPanov/ApplicationCoordinator","owner":"AndreyPanov","description":"Coordinators Essential tutorial","archived":false,"fork":false,"pushed_at":"2022-10-28T08:33:18.000Z","size":450,"stargazers_count":853,"open_issues_count":6,"forks_count":72,"subscribers_count":26,"default_branch":"master","last_synced_at":"2024-12-04T19:39:26.892Z","etag":null,"topics":["application-coordinator","architecture","coordinators","ios","protocols","swift"],"latest_commit_sha":null,"homepage":"https://medium.com/blacklane-engineering/coordinators-essential-tutorial-part-i-376c836e9ba7#.hgv4r6y6p","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AndreyPanov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-21T20:20:38.000Z","updated_at":"2024-10-30T18:50:13.000Z","dependencies_parsed_at":"2023-01-20T13:01:44.069Z","dependency_job_id":null,"html_url":"https://github.com/AndreyPanov/ApplicationCoordinator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AndreyPanov/ApplicationCoordinator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndreyPanov%2FApplicationCoordinator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndreyPanov%2FApplicationCoordinator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndreyPanov%2FApplicationCoordinator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndreyPanov%2FApplicationCoordinator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AndreyPanov","download_url":"https://codeload.github.com/AndreyPanov/ApplicationCoordinator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndreyPanov%2FApplicationCoordinator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267928985,"owners_count":24167431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["application-coordinator","architecture","coordinators","ios","protocols","swift"],"created_at":"2024-01-05T20:15:30.688Z","updated_at":"2025-07-30T19:32:08.218Z","avatar_url":"https://github.com/AndreyPanov.png","language":"Swift","funding_links":[],"categories":["App Routing"],"sub_categories":["Getting Started","Other free courses"],"readme":"# ApplicationCoordinator\nA 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.\n\nBased 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).\n\n\n### Coordinators Essential tutorial. Part I [medium.com](https://medium.com/blacklane-engineering/coordinators-essential-tutorial-part-i-376c836e9ba7)\n\n### Coordinators Essential tutorial. Part II [medium.com](https://medium.com/@panovdev/coordinators-essential-tutorial-part-ii-b5ab3eb4a74)\n\n\nExample provides very basic structure with 6 controllers and 5 coordinators with mock data and logic.\n![](/str.jpg)\n\nI used a protocol for coordinators in this example:\n```swift\nprotocol Coordinator: class {\n    func start()\n    func start(with option: DeepLinkOption?)\n}\n```\nAll flow controllers have a protocols (we need to configure blocks and handle callbacks in coordinators):\n```swift\nprotocol ItemsListView: BaseView {\n    var authNeed: (() -\u003e ())? { get set }\n    var onItemSelect: (ItemList -\u003e ())? { get set }\n    var onCreateButtonTap: (() -\u003e ())? { get set }\n}\n```\nIn this example I use factories for creating  coordinators and controllers (we can mock them in tests).\n```swift\nprotocol CoordinatorFactory {\n    func makeItemCoordinator(navController navController: UINavigationController?) -\u003e Coordinator\n    func makeItemCoordinator() -\u003e Coordinator\n    \n    func makeItemCreationCoordinatorBox(navController: UINavigationController?) -\u003e\n        (configurator: Coordinator \u0026 ItemCreateCoordinatorOutput,\n        toPresent: Presentable?)\n}\n```\nThe base coordinator stores dependencies of child coordinators\n```swift\nclass BaseCoordinator: Coordinator {\n    \n    var childCoordinators: [Coordinator] = []\n\n    func start() { }\n    func start(with option: DeepLinkOption?) { }\n    \n    // add only unique object\n    func addDependency(_ coordinator: Coordinator) {\n        \n        for element in childCoordinators {\n            if element === coordinator { return }\n        }\n        childCoordinators.append(coordinator)\n    }\n    \n    func removeDependency(_ coordinator: Coordinator?) {\n        guard\n            childCoordinators.isEmpty == false,\n            let coordinator = coordinator\n            else { return }\n        \n        for (index, element) in childCoordinators.enumerated() {\n            if element === coordinator {\n                childCoordinators.remove(at: index)\n                break\n            }\n        }\n    }\n}\n```\nAppDelegate store lazy reference for the Application Coordinator\n```swift\nvar rootController: UINavigationController {\n    return self.window!.rootViewController as! UINavigationController\n  }\n  \n  private lazy var applicationCoordinator: Coordinator = self.makeCoordinator()\n  \n  func application(_ application: UIApplication,\n                   didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -\u003e Bool {\n    let notification = launchOptions?[.remoteNotification] as? [String: AnyObject]\n    let deepLink = DeepLinkOption.build(with: notification)\n    applicationCoordinator.start(with: deepLink)\n    return true\n  }\n  \n  private func makeCoordinator() -\u003e Coordinator {\n      return ApplicationCoordinator(\n        router: RouterImp(rootController: self.rootController),\n        coordinatorFactory: CoordinatorFactoryImp()\n      )\n  }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAndreyPanov%2FApplicationCoordinator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAndreyPanov%2FApplicationCoordinator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAndreyPanov%2FApplicationCoordinator/lists"}