Every application consists of the classes that refer to the other classes which refer to the other classes etc. It is a tree of classes where each one knows about its children and doesn't know about its parent.
In general, classes communicate with each other by calling methods and properties of their children to pass data "down" or by triggering a callback passing data "up" to the parent.
Moreover, we have many patterns to make this communication easier such as delegate, facade, observable, command, etc.
Every time the communication must be organized it is up to us to decide which pattern to use, and how to handle it. This requires attention and can easily result in unexpected bugs.
simprokmachine
is a framework that automates the communication between the application's components called "machines".
Machine - is an instance in your application that receives and processes input data and may emit output. It never exists on its own but rather combined with a root machine instance.
To create it use ChildMachine
protocol.
final class PrinterMachine: ChildMachine {
typealias Input = String
typealias Output = Void
var queue: MachineQueue { .main } // defines dispatch queue on which process() method works
func process(input: String?, callback: @escaping Handler<Void>) {
print(input)
}
}
To start the flow use RootMachine
protocol in your top-level class.
extension AppDelegate: RootMachine {
typealias Input = String
typealias Output = Void
var child: Machine<String, Void> {
~PrinterMachine() // or PrinterMachine().machine or Machine(PrinterMachine())
}
}
and don't forget to call start()
to trigger the flow.
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
start()
return true
}
This does not print anything but nil
because after start()
is called the root is subscribed to the child machine triggering process()
method with nil
value.
Use callback: Handler<Output>
to emit output.
final class EmittingMachine: ChildMachine {
typealias Input = String
typealias Output = Void
var queue: MachineQueue { .main }
func process(input: String?, callback: @escaping Handler<Void>) {
if let input = input {
print("input: \(input)")
} else {
callback(Void()) // Emits output
}
}
}
To separate machines into classes instead of cluttering them up in the root - use ParentMachine
protocol.
final class IntermediateLayer: ParentMachine {
typealias Input = String
typealias Output = Void
var child: Machine<String, Void> {
~PrinterMachine()
}
}
To map or ignore input - use inward()
.
... = machine.inward { (parentInput: ParentInput) -> Ward<ChildInput> in
return Ward.set(ChildInput(), ChildInput()) // pass zero, one or more inputs.
}
To map or ignore output - use outward()
.
... = machine.outward { (childOutput: ChildOutput) -> Ward<ParentOutput> in
return Ward.set(ParentOutput(), ParentOutput()) // pass zero, one or more outputs.
}
To send input back to the child when output received - use redirect()
.
... = machine.redirect { (childOutput: ChildOutput) -> Direction<ChildInput> in
// Direction.prop - for pushing ChildOutput further to the root.
// Direction.back([ChildInput]) - for sending child inputs back to the child.
...
}
To merge more than 1 machine together - use merge()
.
let machine1: Machine<Input, Output> = ...
let machine2: Machine<Input, Output> = ...
... = Machine.merge(
machine1,
machine2
)
Check out the sample and the wiki for more information about API and how to use it.
As for now, Swift Package Manager
is the only option to use for adding the framework to your project.
Once you have your Swift package set up, adding simprokmachine
as a dependency is as easy as adding it to the dependencies value of your Package.swift.
dependencies: [
.package(url: "https://github.com/simprok-dev/simprokmachine-ios.git", .upToNextMajor(from: "1.1.2"))
]
Check out these tools to see an existing library of useful machines and the architectural approach we suggest using.
link |
Stars: 0 |
Last commit: 10 weeks ago |
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics