EFStateMachine 0.2.0

EFStateMachine 0.2.0

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布上次发布2015年10月
SPM支持 SPM

Johan KoolJohan Kool 维护。



  • Johan Kool

EFStateMachine.swift

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 添加到您自己的项目中。

示例

假设您想创建状态机来捕获以下图表中的流程

flow diagram

首先,创建一个用于存储状态的枚举。它应遵守 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]

}