SwiftCurrent is a library that lets you easily manage journeys through your Swift application.

When Developing in UIKit, each view controller has to know about the one following it in order to share data. Now imagine a flow where the first 3 screens are optional. What would it look like if you could decouple all of that?

let workflow = Workflow(LocationsViewController.self) // Skip this if you have GPS
                .thenProceed(with: PickupOrDeliveryViewController.self) // Skip this if you only have 1 choice
                .thenProceed(with: MenuSelectionViewController.self) // Skip this for new stores
                .thenProceed(with: FoodSelectionViewController.self)
                .thenProceed(with: ReviewOrderViewController.self) // This lets you edit anything you've already picked
                .thenProceed(with: SubmitPaymentViewController.self)

// from wherever this flow is launched

The above code is all that is needed from the screen starting this flow. Each screen determines if it needs to show based on data passed in and what that screen knows about the system (such as GPS availability), and all of it is type safe. If you ever want to re-order these, simply move their position in the chain.

As you continue to develop your applications, each view controller will become more decoupled from the rest of the app. That means, if you want a completely different order of screens, just define a new Workflow.

See it in action with our example app

Clone our repo, open SwiftCurrent.xcworkspace, target the UIKitExample scheme, and run to see our example app in action.

The example app has a README that details interesting usages.

Interested but you need SwiftUI support?

We're working on it now!

If you would like to try the beta release, please install the BETA_SwiftCurrent_SwiftUI product in SPM or the BETA_SwiftUI sub spec in CocoaPods. For more detailed steps, see our installation instructions. See Getting Started with SwiftUI for a quick tutorial. To see the example app for SwiftUI, clone our repo, open SwiftCurrent.xcworkspace, target the SwiftUIExample scheme, and run. The example app has a README that details interesting usages.

In order to use the library with SwiftUI, your minimum targeted versions must meet: iOS 14.0, macOS 11, tvOS 14.0, or watchOS 7.0.

For us, beta means that the API may change without warning until the full release. However, we expect bugs to be at a minimum and documentation to be true and accurate.

Quick Start

This quick start uses SPM, but for other approaches, see our installation instructions.


.package(url: "https://github.com/wwt/SwiftCurrent.git", .upToNextMajor(from: "4.0.0")),
.product(name: "SwiftCurrent", package: "SwiftCurrent"),
.product(name: "SwiftCurrent_UIKit", package: "SwiftCurrent")

Then make your first FlowRepresentable view controllers:

import SwiftCurrent
import SwiftCurrent_UIKit
class OptionalViewController: UIWorkflowItem<String, Never>, FlowRepresentable {
    let input: String
    required init(with args: String) {
        input = args
        super.init(nibName: nil, bundle: nil)
    required init?(coder: NSCoder) { nil }
    override func viewDidLoad() { view.backgroundColor = .blue }
    func shouldLoad() -> Bool { input.isEmpty }
class ExampleViewController: UIWorkflowItem<Never, Never>, FlowRepresentable {
    override func viewDidLoad() { view.backgroundColor = .green }

Then from your root view controller, call:

import SwiftCurrent
let workflow = Workflow(OptionalViewController.self)
    .thenProceed(with: ExampleViewController.self)
launchInto(workflow, args: "Skip optional screen")

And just like that you're started!

[BETA] SwiftUI

.package(url: "https://github.com/wwt/SwiftCurrent.git", .upToNextMajor(from: "4.1.0")),
.product(name: "SwiftCurrent", package: "SwiftCurrent"),
.product(name: "BETA_SwiftCurrent_SwiftUI", package: "SwiftCurrent")

Then make your first FlowRepresentable view:

import SwiftCurrent
struct ExampleView: View, FlowRepresentable {
    weak var _workflowPointer: AnyFlowRepresentable?
    let input: String
    init(with args: String) { input = args }
    var body: some View { Text("Passed in: \(input)") }
    func shouldLoad() -> Bool { !input.isEmpty }

Then from your ContentView body, add:

import SwiftCurrent_SwiftUI
WorkflowLauncher(isLaunched: .constant(true), startingArgs: "Launched")
    .thenProceed(with: WorkflowItem(ExampleView.self))

And just like that you're started!