Component implementation structure - Swift
Create a simple non-ui component
Component Structure
The component is comprised of a swift class which implements the functionality of the component. The class can call on other classes, and additional functionality beyond the main class to implement the component.
In cases where UI is also associated with a component, additional structs which represent the UI view is implemented.
Component Protocol
A component that will be consumed and usable by the SDK must conform to a ComponentSubscriber protocol.
The ComponentSubscriber
protocol ensures that the component implements several required functions and variables to make the component compatible with the SDK.
Basic code structure
The following is a basic implementation of the required functions of a component
import CloneableCore
import CloneablePlatformiOS
public class SampleComponent: ComponentSubscriber {
// Required properties properties
var staticComponentID: String
var dynamicComponentID: String
var component: DeployedWorkflow_components
// Implementing protocol functions
// Called just prior to the platform sending it's first inputs to the component
required init(dynamicComponentID: String, staticComponentID: String, component: DeployedWorkflow_components) {
self.dynamicComponentID = dynamicComponentID
self.staticComponentID = staticComponentID
self.component = component
// Additional logic to run when init is called can be placed here
...
// Required call to register this instance of the component with the cloneable framework
// workflowFramework is a global variable which holds reference to the framework which is running the workflows
workflowFramework?.subscribeComponent(subscriber: self, dynamicComponentID: dynamicComponentID, staticComponentID: staticComponentID)
}
public func componentWillDeInit(final: Bool) {
// Handle de-initialization logic here
}
public func acceptNewInputs(inputs: [DataInput]) {
// Handle new inputs here
}
}
staticComponentID
The static component id is the unique id (uuidV4) of the component's definition.
dynamicComponentID
This unique id (uuidV4) that is assigned to the component at the time of workflow compile in the builder. This allows you to differentiate individual components in a workflow if their are multiple of the same component in the workflow
component: DeployedWorkflow_components
The full JSON definition of the component. This will have all of the information about the component, inputs, outputs, and customizable parameters for the component as they are defined by the user in the builder
Workflow Component TypeSubscribe to the workflow framework
In order for the Cloneable SDK to use a component implementation during a workflow, the component must subscribe itself to the workflowFramework
when it is ready to begin receiving inputs.
In most cases it's best to subscribe at the end of the init when everything in the component is setup. In some complex cases you may have asynchronous tasks occurring which need to complete to setup the component before it is ready to accept inputs (ie. loading an AI model)
// Call subscribeComponent and pass self as the subscriber along with the component ids
workflowFramework!.subscribeComponent(subscriber: self, dynamicComponentID: dynamicComponentID, staticComponentID: staticComponentID)
Accepting Inputs
The framework will call the acceptNewInputs
function in the component when inputs are being passed to the component.
Grouping of inputs
The inputs will arrive as an array of Data Input, each data input represents a single input from a single outputs. When inputs arrive together in the same array in a singular function call, we consider those inputs to be grouped into a batch together. Grouping of inputs allows you to process the inputs in advanced ways.
See:How Data Flowsfor more information.
See: Data Input for more information on how Data inputs are structured
Working with the input data
Access the data in the input at input.data
. The data is stored in a type unwrapped AnyCloneableData
read more about AnyCloneableData
here: AnyCloneableData
Below is an example of parsing a String data type from AnyCloneableData
func acceptNewInputs(inputs: [DataInput]) {
if let input = inputs.first { // usually you will want to get the input by its inputID
let inputDataType: String = input.data.getTypeAsString()
}
}
Sending Outputs
You can send outputs from your component at any point in it's life cycle. You may also send any individual inputs at any point as there are not requirements to send all inputs at the same time. However, it is good practice to send inputs at the same time that share a group id together as this is represented in the UI of the builder together.
Outputs are sent as Data Output. See the reference for more detailed information on data references.
Data outputs must be AnyCloneableData
See usage here:
Call the output function on workflowFramework
Send your outputs as an array of DataOutput
's to workflowFramework.sendOutputsToFramework
Below is a basic example for outputting data from a single output to the SDK:
import CloneableCore
import CloneablePlatformiOS
public class SampleComponent: ComponentSubscriber {
// Required properties properties
var staticComponentID: String
var dynamicComponentID: String
var component: DeployedWorkflow_components
...
// function which will be called by our component to process and send an output
func sendAnOutput() {
// we need to get the dynamicID of the output that we are going to send
// we are going to do this, by filtering the outputs from the component
// to find the input with the id
if let outputId = component.outputs.first(where: {$0.outputId == "5b7dc149-2682-45e4-8da5-772f8ffe17fa"})?.dynamicOutputId {
// create the AnyCloneableData to wrap the string data we are going to send
let data = AnyCloneableData(data: CloneableString("This is my output"))
// construct the output
let output = DataOutput(
data: data,
staticComponentID: staticComponentID,
dynamicComponentID: dynamicComponentID,
dynamicOutputID: outputId,
outputComponentType: .processing)
// send the output to the framework
workflowFramework?.sendOutputsToFramework(outputs: [output])
}
}
}
Notifying the component that it will de-initialize
The platform will call the componentWillDeInit
function within our component prior to the component being de-initialized. The platform will also pass final
if the component is going to go out of scope for a while or if it will be permanently de-initialized.
Last updated