FlowRepresentable

public protocol FlowRepresentable

A component in a Workflow; should be independent of the workflow context.

Discussion

It’s important to make sure your FlowRepresentable is not dependent on other FlowRepresentables. It’s okay to specify that a certain kind of data needs to be passed in and passed out, but keep your FlowRepresentable from knowing what came before, or what’s likely to come after. In that way you’ll end up with pieces of a workflow that can be moved or put into multiple places with ease.

Important

Declare an input type of Never when the FlowRepresentable will ignore data passed in from the Workflow. An output type of Never means data will not be passed forward.

Important

A _workflowPointer has to be declared as a property on the type conforming to FlowRepresentable but it is set by the Workflow, and should not be set by anything else.

Important

If you create a superclass that is a FlowRepresentable and expect subclasses to be able to define their own methods, such as shouldLoad, the superclass should declare those methods, and the subclasses should override them. Otherwise you will find the subclasses do not behave as expected.

Example

A FlowRepresentable with a WorkflowInput of String and a WorkflowOutput of Never

class FR1: FlowRepresentable { // Mark this class as `final` to avoid the required keyword on init
   weak var _workflowPointer: AnyFlowRepresentable?
   required init(with name: String) { }
}

A FlowRepresentable with a WorkflowInput of Never and a WorkflowOutput of Never

final class FR1: FlowRepresentable { // Classes synthesize an empty initializer already, you are good!
   weak var _workflowPointer: AnyFlowRepresentable?
}

Note

Declaring your own custom initializer can result in a compiler error with an unfriendly message.

class FR1: FlowRepresentable { // Results in compiler error for 'init()' being unavailable
   weak var _workflowPointer: AnyFlowRepresentable?
   init(myCustomInitializer property: Int) { }
   // required init() { } // declare your own init() to satisfy the protocol requirements and handle the compiler error
}
  • The type of data coming into the FlowRepresentable; defaulted to Never; Nevermeans the FlowRepresentable will ignore data passed in from the Workflow.

    Declaration

    Swift

    associatedtype WorkflowInput = Never
  • The type of data passed forward from the FlowRepresentable; defaulted to Never; Never means data will not be passed forward.

    Declaration

    Swift

    associatedtype WorkflowOutput = Never
  • A pointer to the AnyFlowRepresentable that erases this FlowRepresentable; will automatically be set.

    Discussion

    This property is automatically set by a Workflow; it simply needs to be declared on a FlowRepresentable. In order for a FlowRepresentable to have access to the Workflow that launched it, store the closures for proceeding forward and backward, and provide type safety. It needs this property available for writing.

    Note

    While not strictly necessary, it would be wise to declare this property as weak.

    Declaration

    Swift

    var _workflowPointer: AnyFlowRepresentable? { get set }
  • Creates a FlowRepresentable.

    Note

    This is auto-synthesized by FlowRepresentable, and is only called when WorkflowInput is Never.

    Declaration

    Swift

    init()
  • Creates a FlowRepresentable with the specified WorkflowInput.

    Declaration

    Swift

    init(with args: WorkflowInput)
  • shouldLoad() Default implementation

    Returns a Boolean indicating the Workflow should load the FlowRepresentable; defaults to true.

    Discussion

    This method is called after init but before any other lifecycle events. It is non-mutating and should not change the FlowRepresentable.

    Important

    If you create a superclass that is a FlowRepresentable and expect subclasses to define their own shouldLoad, the superclass should declare shouldLoad, and the subclasses should override it. Otherwise you will find the subclasses do not behave as expected.

    Note

    Returning false can have different behaviors depending on the FlowPersistence.

    Default Implementation

    Declaration

    Swift

    func shouldLoad() -> Bool
  • workflow Extension method

    Access to the AnyWorkflow controlling the FlowRepresentable.

    Discussion

    A common use case may be a FlowRepresentable that wants to abandon the Workflow it’s in.

    Declaration

    Swift

    public var workflow: AnyWorkflow? { get }
  • proceedInWorkflow(_:) Extension method

    Moves forward while passing arguments forward in the Workflow; if at the end, calls the onFinish closure used when launching the workflow.

    Declaration

    Swift

    public func proceedInWorkflow(_ args: WorkflowOutput)
  • backUpInWorkflow() Extension method

    Backs up in the Workflow.

    Throws

    WorkflowError when the Workflow is unable to back up.

    Declaration

    Swift

    public func backUpInWorkflow() throws

Available where WorkflowOutput == Never

  • proceedInWorkflow() Extension method

    Moves forward in the Workflow; if at the end, calls the onFinish closure used when launching the workflow.

    Declaration

    Swift

    public func proceedInWorkflow()
  • proceedInWorkflow(_:) Extension method

    Moves forward while passing arguments forward in the Workflow; if at the end, calls the onFinish closure used when launching the workflow.

    Declaration

    Swift

    public func proceedInWorkflow(_ args: WorkflowOutput)

Available where Self: UIViewController

  • Called when the current workflow should be terminated, and the app should return to the point before the workflow was launched.

    Note

    In order to dismiss UIKit views, the workflow must have an OrchestrationResponder that is a UIKitPresenter.

    Declaration

    Swift

    public func abandonWorkflow(animated: Bool = true, onFinish: (() -> Void)? = nil)

    Parameters

    animated

    a boolean indicating whether abandoning the workflow should be animated.

    onFinish

    a callback after the workflow has been abandoned.