Swordinator is a simple way of integrating an iOS Coordinator pattern.

Overview

Swordinator: Minimal Coordinator Pattern for Swift

Swordinator is a minimal, lightweight and easy customizable navigation framework for iOS applications.

Tests

Requirements

iOS 14.0+, Swift 5.0+

Installation

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/laubengaier/Swordinator.git", .upToNextMajor(from: "1.0.0"))
]

Use Swordinator

These steps should provide a simple way of getting started. If something is not clear please take a look at the demo provided or create an issue.

Quicknote:

The simplest way is to go forward with implementing Step and using handle(step: Step) which simplifies the coordination but if you want even more control or don't like steps there is a delegate example in the demo (NoStepCoordinator).

1. Define Steps

Create a new class called AppStep or anything you like that will define the steps your application can do.

enum AppStep: Step 
{
    // task list
    case taskList
    
    // task detail
    case taskDetail
    case taskDetailCompleted
    
    // auth
    case auth
    case authCompleted
    case logout
}

2. Setup AppCoordinator

Create a new class called AppCoordinator or similar that defines the entry point to your app.

class AppCoordinator: Coordinator 
{
    let window: UIWindow
    var rootCoordinator: Coordinator?
    var childCoordinators: [Coordinator] = []
    
    let services: AppServices
    
    init(window: UIWindow, services: AppServices) {
        self.window = window
        self.services = services
        start()
    }
    
    func start() {
        if services.isAuthenticated {
            self.showTaskList()
        } else {
            self.showLogin()
        }
    }
    
    func handle(step: Step) {
        guard let step = step as? AppStep else { return }
        switch step {
        case .auth:
            showLogin()
        case .taskList:
            showTaskList()
        default:
            return
        }
    }
}

extension AppCoordinator 
{
    private func showLogin() {
        // show login
    }
    
    private func showTaskList() {
        let nvc = UINavigationController()
        let coordinator = TaskListCoordinator(navigationController: nvc, services: services)
        coordinator.parent = self
        rootCoordinator = coordinator
        window.rootViewController = nvc
    }
}

3. AppDelegate / Scene

class SceneDelegate: UIResponder, UIWindowSceneDelegate 
{

    var window: UIWindow?
    var appCoordinator: AppCoordinator?
    let appServices = AppServices()

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            appCoordinator = AppCoordinator(window: window, services: appServices)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
    
    // ...
}

Deeplinks

If you want to support deeplinks in your application you just need to let your Coordinator classes adapt to Deeplinkable as following:

class AppCoordinator: Coordinator, Deeplinkable {

    //...
    var rootCoordinator: (Coordinator & Deeplinkable)?
    
    //...
    
    func handle(deepLink: DeeplinkStep) {
        if let root = rootCoordinator {
            root.handle(deepLink: deepLink)
        }
    }
}

This comes in pretty handy when dealing with Universal Links or Push Notifications. The rootCoordinator should be seen as the current active Coordinator so if there is a event then it can be forwarded to the top most active coordinator or handled anywhere in between.

In the Demo application there is a taskDetail deeplink that will be forwarded to either the TaskList or Profile and handled there.

Illustrated here Demo Flow

Important Notice

Memory Leaks

To avoid memory leaks you should pay attention to releasing the Coordinators from childCoordinators when they are not used anymore.

For Example:

func handle(step: Step) {
    guard let step = step as? AppStep else { return }
    switch step {
    case .taskDetailCompleted:
        childCoordinators.removeAll { $0 is TaskDetailCoordinator }
    }
}

Demo Application

A demo is provided to show the core mechanics and how to apply the coordinator pattern.

Login Dashboard Profile

Deeplinks

Run the following commands in your terminal to test deeplinks with the simulator

# lazy load and show a task
xcrun simctl openurl booted swordinator://tasks/1
# taskList, switch tab
xcrun simctl openurl booted swordinator://tasks
# profile, switch tab
xcrun simctl openurl booted swordinator://profile
# profile settings, switch tab to profile and open settings
xcrun simctl openurl booted swordinator://settings
# logout
xcrun simctl openurl booted swordinator://logout

Pattern

Demo Flow

This is an illustration of how the pattern is used in the demo application

SwordinatorExampleFlow

Mentions

RxFlow This project is inspired by RxFlow which is a great way to use Coordinators in a reactive manner but imho it's not always clear what is happening behind the scenes so this project should provide a more simplified way to integrate and gain more control.

License

This code is distributed under the MIT license. See the LICENSE file for more info.

You might also like...
A declarative, thread safe, and reentrant way to define code that should only execute at most once over the lifetime of an object.

SwiftRunOnce SwiftRunOnce allows a developer to mark a block of logic as "one-time" code – code that will execute at most once over the lifetime of an

A way to represent what you’re sharing.
A way to represent what you’re sharing.

About This project provides a preview of items being shared via UIActivityViewController. Example: // standard activity view controller let vc = UIAct

A quick and "lean" way to swizzle methods for your Objective-C development needs.

Swizzlean A quick and "lean" way to swizzle methods for your Objective-C development needs. Adding Swizzlean to your project Cocoapods CocoaPods is th

Testable Combine Publishers - An easy, declarative way to unit test Combine Publishers in Swift
Testable Combine Publishers - An easy, declarative way to unit test Combine Publishers in Swift

Testable Combine Publishers An easy, declarative way to unit test Combine Publishers in Swift About Combine Publishers are notoriously verbose to unit

Updeto is a simple package that help update checker for iOS Apps

Updeto is a simple package that will help you to check if the currently installed version is the same as the latest one available on App Store.

Simple and Lightweight App Version Tracking for iOS written in Swift

AEAppVersion Simple and lightweight iOS App Version Tracking written in Swift I made this for personal use, but feel free to use it or contribute. For

Unit-Converter-SwiftUI - A simple Unit Converter iOS app built in the process of learning SwiftUI
Unit-Converter-SwiftUI - A simple Unit Converter iOS app built in the process of learning SwiftUI

SwiftUI-Unit-Converter A simple Unit Converter iOS app built in the process of l

 Zip - A Swift framework for zipping and unzipping files. Simple and quick to use. Built on top of minizip.
Zip - A Swift framework for zipping and unzipping files. Simple and quick to use. Built on top of minizip.

Zip A Swift framework for zipping and unzipping files. Simple and quick to use. Built on top of minizip. Usage Import Zip at the top of the Swift file

RandomKit is a Swift framework that makes random data generation simple and easy.
RandomKit is a Swift framework that makes random data generation simple and easy.

RandomKit is a Swift framework that makes random data generation simple and easy. Build Status Installation Compatibility Swift Package Manager CocoaP

Comments
  • start step refactoring (improvements)

    start step refactoring (improvements)

    • add step to the start method to handle initial steps
    • add an id to the coordinator for improved future child removal
    • Example: changed login view model to use Coordinated instead of the View itself
    • improved logging
    • iOS 13 support
    opened by laubengaier 0
  • Reuseable Navigation Actions

    Reuseable Navigation Actions

    Description

    Slight changes

    What changed

    • changed ParentCoordinated to AnyParentCoordinated and let ParentCoordinated adapt parent as Coordinator
    • added basic unit tests
    • added reusable navigation actions to AppStep for taskDetail
    • iOS 14 support
    • bit of cleanup, move NavCoordinator and AppDeeplinkStep+Convert to Helper folder
    opened by laubengaier 0
  • Advanced Flow

    Advanced Flow

    Description

    Enable xcrun simctl openurl booted swordinator://settings deeplink to trigger from the Task Detail view and implement proper step details

    • add profileSettings deeplink to move to profileSettings (even when in taskDetail)
    • replace profile settings menu barbutton with showing an actual ProfileSettings vc
    opened by laubengaier 0
Releases(1.2.0)
  • 1.2.0(Mar 7, 2022)

    • add step to the start method to handle initial steps
      • start() changed to start(step: Step)
    • add an id to the coordinator for improved future child removal
    • example: changed login ViewModel to use Coordinated instead of the View itself
    • improved logging styling
    • iOS 13 support
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Oct 19, 2021)

    • changed ParentCoordinated to AnyParentCoordinated
    • AnyParentCoordinated is now used as a generic parent coordinator and ParentCoordinated is used with parent specified as Coordinator to add some functionalities
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Oct 14, 2021)

Owner
Timotheus Laubengaier
iOS Freelancer and Swift Enthusiast
Timotheus Laubengaier
FluxCapacitor makes implementing Flux design pattern easily with protocols and typealias.

FluxCapacitor makes implementing Flux design pattern easily with protocols and typealias. Storable protocol Actionable protocol Dispatch

Taiki Suzuki 123 Aug 23, 2022
A SARS-CoV-2 Mutation Pattern Query Tool

vdb A SARS-CoV-2 Mutation Pattern Query Tool 1. Purpose The vdb program is designed to query the SARS-CoV-2 mutational landscape. It runs as a command

null 13 Oct 25, 2022
A meta library to provide a better `Delegate` pattern.

Delegate A meta library to provide a better Delegate pattern described here and here. Usage Instead of a regular Apple's protocol-delegate pattern, us

Wei Wang 67 Dec 23, 2022
🚀Comprehensive Redux library for SwiftUI, ensures State consistency across Stores with type-safe pub/sub pattern.

??Comprehensive Redux library for SwiftUI, ensures State consistency across Stores with type-safe pub/sub pattern.

Cheng Zhang 18 Mar 9, 2022
Simple way to set up half modal view

HalfModalView Requirements iOS 9.0+ Xcode 10.0+ Swift 4.0+ Example Installation CocoaPods is a dependency manager for Cocoa projects. You can install

Choi SeungMyeong 5 Nov 14, 2022
A way to easily add Cocoapod licenses and App Version to your iOS App using the Settings Bundle

EasyAbout Requirements: cocoapods version 1.4.0 or above. Why you should use Well, it is always nice to give credit to the ones who helped you ?? Bonu

João Mourato 54 Apr 6, 2022
Easy way to detect iOS device properties, OS versions and work with screen sizes. Powered by Swift.

Easy way to detect device environment: Device model and version Screen resolution Interface orientation iOS version Battery state Environment Helps to

Anatoliy Voropay 582 Dec 25, 2022
The simplest way to display the librarie's licences used in your application.

Features • Usage • Translation • Customisation • Installation • License Display a screen with all licences used in your application can be painful to

Florian Gabach 51 Feb 28, 2022
The fastest 🚀 way to embed a 3D model in Swift

Insert3D is the easiest ?? and fastest ?? way to embed a 3D model in your iOS app. It combines SceneKit and Model I/O into a simple library for creati

Viktor Makarskyy 85 Dec 31, 2022
XCMetrics is the easiest way to collect Xcode build metrics and improve developer productivity.

XCMetrics is the easiest way to collect Xcode builds metrics and improve your developer productivity. Overview ?? Keep your build times under control

Spotify 989 Jan 2, 2023