测试已测试 | ✓ |
语言语言 | SwiftSwift |
许可证 | MIT |
发布上次发布 | 2015年10月 |
SPM支持 SPM | ✗ |
由 Johan Kool,Johan Kool 维护。
Swift 中的简单状态机
此状态机的亮点:
通常用枚举设置状态机的可能状态,并且用枚举设置其动作。状态机的状态决定了动作是否允许运行。状态机只能通过动作更改状态。动作处理器返回状态机的新的状态。
还可能注册多个处理程序,在发生某些状态更改时运行。
您需要至少 iOS 8.0 或 Mac OS X 10.9。
此实现是使用 Swift 2.0 编写的。如果您仍然需要 Swift 1.2 的支持,请使用版本 0.1.5。
API 已完全在源中进行文档编制。请参阅下面的示例。
要使用 CocoaPods,请将其添加到您的 Podfile:
pod 'EFStateMachine', '~> 0.2'
或者您只需编译源代码并将 StateMachine.framework
添加到您自己的项目中。
假设您想创建状态机来捕获以下图表中的流程
首先,创建一个用于存储状态的枚举。它应遵守 Hashable
协议。建议使用 String
类型的枚举。
enum LoadState: String {
case Empty
case Loading
case Complete
case Failed
}
声明动作的枚举以相同的方式。
enum LoadAction: String {
case Load
case FinishLoading
case Cancel
case Reset
}
现在我们已经有了一系列的状态和动作,我们可以创建机器并给它一个初始状态。
let machine = StateMachine<LoadState, LoadAction>(initialState: .Empty)
对于每个动作,注册一个要运行的处理程序。只有当状态机的当前状态是 fromStates
中列出的状态之一时,才会运行处理程序。处理程序必须返回一个状态,它将成为状态机的新状态。
machine.registerAction(.Load, fromStates: [.Empty, .Failed], toStates: [.Loading]) { (machine) -> LoadState in
return .Loading
}
machine.registerAction(.FinishLoading, fromStates: [.Loading], toStates: [.Complete, .Failed]) { (machine) -> LoadState in
return .Complete // (or return .Failed if that's the case)
}
machine.registerAction(.Reset, fromStates: [.Complete, .Failed], toStates: [.Empty]) { (machine) -> LoadState in
return .Empty
}
由于状态机跟踪其状态历史,您可以实现处理取消异步任务的方法。
machine.registerAction(.Cancel, fromStates: [.Loading], toStates: [.Empty, .Failed]) { (machine) -> LoadState in
return machine.history[machine.history.count - 2]
}
您还可以观察状态更改并对此类事件做出反应。这也是提醒您不要引入保留循环的好时机。如果 self
含有状态机,则应使用 [unowned self
或 [weak self]
与您的处理程序。
machine.onChange(toStates: [.Complete]) { [unowned self] (machine, oldState, newState) -> Void in
self.infoLabel.text = "Complete!"
}
现在您的状态机已准备就绪,可以开始使用了。执行操作非常简单。如果您收到了一个状态,则表示操作已执行;如果返回的是nil
,则表示该操作被忽略了。
// Start loading
machine.performAction(.Load) // returns .Loading
// Loading finished
machine.performAction(.FinishLoading) // returns .Complete and updates infoLabel to "Complete!"
// Try loading again (an invalid action)
machine.performAction(.Load) // returns nil
要得到上面显示的流程图,您需要将flowdiagramRepresentation
属性返回的字符串保存到dot文件中。您可以使用免费的App GraphViz 展示该图。
do {
try machine.saveFlowdiagramRepresentationToPath("/path/to/example-flow-diagram.dot")
} catch let error {
NSLog("Could not save flowdiagram: \(error)")
}
这将创建一个包含以下内容的文件
digraph {
graph [rankdir=TB]
0 [label="", shape=plaintext]
0 -> 1
# node
1 [label="Empty", shape=box]
2 [label="Loading", shape=box]
3 [label="Cancel", shape=oval]
4 [label="Load", shape=oval]
5 [label="Complete", shape=box]
6 [label="FinishLoading", shape=oval]
7 [label="Failed", shape=box]
8 [label="Reset", shape=oval]
# links
2 -> 3 [arrowhead=none]
3 -> 1
1 -> 4 [arrowhead=none]
4 -> 2
2 -> 6 [arrowhead=none]
6 -> 5
6 -> 7
5 -> 8 [arrowhead=none]
8 -> 1
7 -> 8 [arrowhead=none]
}