DDStateMachine
对该已知旧状态机的松散解释
介绍
DDStateMachine 有主要组件
- StateMachineBuilder. 可以通过 StateMachineBuilder 初始化状态机,它提供了一个灵活的接口来创建不同状态序列及其关系。
- StateBuilder. 框架不提供对状态的直接访问,但仍需要创建它以描述关系及其动作(工作)。
- StateMachine. 创建状态机后,可以为发送事件来更改状态机的当前状态和观察当前状态的变化提供一种可能性。
- Event. 事件是操作状态机的命令,开发人员可以注册带有事件的状态机,状态机会对该事件进行处理(我们建议使用枚举)。如果当前步骤可以处理此事件,它将切换所需的转换。
- Transition. 状态之间的关系称为转换,它们可以在构建状态机时注册。
- Extra State. 即使最简单的系统也有许多难以注册的状态,例如独立状态。在这种情况下,我们可以使用额外状态。这是一个特定的数据类,可以附加到每个状态,并可以在状态的工作块内处理。
- 结果条件。 不仅事件可以切换转换,如果一个状态执行一些工作,我们还可以注册结果条件。在这种情况下,我们可以使用工作的结果来做出决定:是否运行特定的转换。
- On 条件。 我们可以在特定的转换上注册特定的监听器,当此转换完成时,它们将被调用,在运行第二个状态的工作之前。
- If 条件。 我们可以使用 If 条件扩展转换,这些转换将使用特定事件调用。在这种情况下,即使状态机接收到所需的事件,它还需要“如果条件”的成功结果。
示例
让我们为同步过程创建一个状态机。我们的同步过程包含以下状态
- 未同步
- 进行中
- 同步
- 失败
在这种情况下,状态机将只处理一个外部事件 "sync",此外,为了防止同步工作频繁调用,我们在可以过渡到进行中的状态之前引入了30秒的缓存生存期。
以下是图表
在代码中将是这样的
数据结构
enum SyncStatus: Int, Hashable {
case notSynced
case inProgress
case synced
case failed
}
enum SyncEvent {
case sync
}
class SyncExtraState: ExtraStateProtocol {
var expiryDate: Date?
required init() {
}
}
状态机属性
private var stateMachine: StateMachine<SyncStatus, SyncEvent>?
// This property will be used for observing
var currentStatus: Property<SyncStatus> {
return self.stateMachine!.currentStatus
}
描述状态机
// Scheduler will be used for running states' works
let builder = StateMachineBuilder<SyncStatus, SyncEvent, SyncExtraState>(scheduler: QueueScheduler())
let notSynced: StateBuilder<SyncStatus, SyncEvent, SyncExtraState> = StateBuilder(.notSynced)
let synced: StateBuilder<SyncStatus, SyncEvent, SyncExtraState> = StateBuilder(.synced)
let failed: StateBuilder<SyncStatus, SyncEvent, SyncExtraState> = StateBuilder(.failed)
// For describing states with "Work" we need to use a special type of StateBuilder - WorkStateBuilder.
let inProgress: WorkStateBuilder<SyncStatus, SyncEvent, SyncExtraState, ResultDomainModel<Void>> =
WorkStateBuilder(.inProgress, work: self.doSync)
// If the state machine is in Not Synced state and gets the event "sync"
// it will transit to In Progress state immediately.
builder.shouldTransit(notSynced ~> inProgress).by(event: .sync).immediately()
// If the state machine is in In Progress state and In Progress work returns true
// the state machine will transit to Synced state immediately.
// After the transition it will call "on" condition for synced State (It sets SyncExtraState->expiryDate to now + 30 seconds).
builder.shouldTransit(inProgress ~> synced)
.on { $0.expiryDate = Date() + 10.seconds }
.ifResult { (result, _) in result }
// If the state machine is in In Progress state and In Progress work returns false
// the state machine will transit to Failed state immediately.
builder.shouldTransit(inProgress ~> failed).ifResult { (result, _) in !result }
// If the state machine is in Synced state and gets the event "sync" and if cache has expired
// then if all conditions fulfilled it will transit to In Progress state immediately.
builder.shouldTransit(synced ~> inProgress)
.by(event: .sync)
.ifCondition { $0.expiryDate == nil || $0.expiryDate! < Date() }
// If the state machine is in Failed state and gets the event "sync"
// it will transit to In Progress state immediately.
builder.shouldTransit(failed ~> inProgress).by(event: .sync).immediately()
// Create the state machine with initial state Not Synced
self.stateMachine = builder.build(initialState: notSynced)
同步工作方法
func doSync() -> SignalProducer<Bool, NoError> {
// Write some sycnronization code
}
设置“同步”事件
func sync() {
self.stateMachine?.execute(event: .sync)
}
此示例使用 SwiftDate 用于日期处理和 ReactiveSwift 用于调度。
已知问题
以下是一些已知问题的列表(请参阅单元测试以获取额外细节)
- 如果初始状态是工作状态,状态机将不会运行其工作。
- 如果状态机是循环的,并且最后一个状态包含工作,状态机将不会运行其工作。
要求
- iOS 10.3+
- Xcode 9.4+
- Swift 4.1+
安装
CocoaPods
如果您使用 CocoaPods 管理依赖项,只需将 DDStateMachine 添加到您的 Podfile 中
pod 'DDStateMachine', '~> 1.0'
Carthage
Carthage 是一种去中心化的依赖项管理器,用于构建您的依赖项并提供二进制框架。
您可以使用以下命令通过 Homebrew 安装 Carthage
$ brew update
$ brew install carthage
要使用 Carthage 将 DDStateMachine 集成到您的 Xcode 项目中,请在您的 Cartfile
中指定它
github "DeadDogDeus/DDStateMachine" ~> 1.0
运行 carthage update
构建框架,并将构建的 DDStateMachine.framework
拖到您的 Xcode 项目中。