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 FlowRepresentable
s. 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 ofNever
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 aFlowRepresentable
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 toNever
;Never
means theFlowRepresentable
will ignore data passed in from theWorkflow
.Declaration
Swift
associatedtype WorkflowInput = Never
-
The type of data passed forward from the
FlowRepresentable
; defaulted toNever
;Never
means data will not be passed forward.Declaration
Swift
associatedtype WorkflowOutput = Never
-
A pointer to the
AnyFlowRepresentable
that erases thisFlowRepresentable
; will automatically be set.Discussion
This property is automatically set by a
Workflow
; it simply needs to be declared on aFlowRepresentable
. In order for aFlowRepresentable
to have access to theWorkflow
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
isNever
.Declaration
Swift
init()
-
Creates a
FlowRepresentable
with the specifiedWorkflowInput
.Declaration
Swift
init(with args: WorkflowInput)
-
shouldLoad()
Default implementationReturns a Boolean indicating the
Workflow
should load theFlowRepresentable
; defaults totrue
.Discussion
This method is called after
init
but before any other lifecycle events. It is non-mutating and should not change theFlowRepresentable
.Important
If you create a superclass that is aFlowRepresentable
and expect subclasses to define their ownshouldLoad
, the superclass should declareshouldLoad
, 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 theFlowPersistence
.Default Implementation
Declaration
Swift
func shouldLoad() -> Bool
-
workflow
Extension methodAccess to the
AnyWorkflow
controlling theFlowRepresentable
.Discussion
A common use case may be a
FlowRepresentable
that wants to abandon theWorkflow
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 theonFinish
closure used when launching the workflow.Declaration
Swift
public func proceedInWorkflow(_ args: WorkflowOutput)
-
backUpInWorkflow()
Extension methodBacks up in the
Workflow
.Declaration
Swift
public func backUpInWorkflow() throws
-
proceedInWorkflow()
Extension methodMoves forward in the
Workflow
; if at the end, calls theonFinish
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 theonFinish
closure used when launching the workflow.Declaration
Swift
public func proceedInWorkflow(_ args: WorkflowOutput)
-
flowRepresentableName
Extension methodThe name of the
FlowRepresentable
as used in the Workflow Data SchemeDeclaration
Swift
public static var flowRepresentableName: String { get }
-
metadataFactory(launchStyle:
Extension methodflowPersistence: ) Creates a new instance of
FlowRepresentableMetadata
Declaration
Swift
public static func metadataFactory(launchStyle: LaunchStyle, flowPersistence: @escaping (AnyWorkflow.PassedArgs) -> FlowPersistence) -> FlowRepresentableMetadata
-
abandonWorkflow(animated:
Extension methodonFinish: ) 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 anOrchestrationResponder
that is aUIKitPresenter
.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.