Swift StateMachine源码分析
状态机的描述如下图:
swift的StateMachine的源码是Transporter。比较简单,只有3个文件。
Event指事件,State指状态,StateMachine是状态机控制中心。
State
public class State {
/// Value of state
public let value : T
/// Closure, that will be executed, before state machine enters this state
public var willEnterState: ( (enteringState : State ) -> Void)?
/// Closure, that will be executed, after state machine enters this state
public var didEnterState: ( (enteringState : State ) -> Void)?
/// Closure, that will be executed before state machine will switch from current state to another state.
public var willExitState: ( (exitingState : State ) -> Void)?
/// Closure, that will be executed after state machine switched from current state to another state.
public var didExitState: ( (exitingState : State ) -> Void)?
/// Create state with value
/// - Parameter value: value of state
public init(_ value: T) {
self.value = value
}
}
value:用来标识状态。
willEnterState:即将进入状态state
didEnterState:已经进入状态state
willExitState:即将脱离状态state
didExitState:已经脱离状态state
Event
public class Event {
/// Name of event
public let name : String
/// Array of source values, in which event can be fired
public let sourceValues: [T]
/// Destination value for state, to which state machine will switch after firing event.
public let destinationValue: T
/// If this closure return value is false, event will not be fired
public var shouldFireEvent: ( (event : Event) -> Bool )?
/// This closure will be executed before event is fired.
public var willFireEvent: ( (event : Event) -> Void )?
/// This closure will be executed after event was fired.
public var didFireEvent: ( (event : Event) -> Void )?
}
name定义了事件的名称
sourceValues:事件的起始状态,为什么要用一个数组呢?猜想是因为到另外一个状态的转换,可以是由不同的状态转换而来。如下图C可由A,B转换而来。
destinationValue:事件的目的状态
shouldFireEvent:是否允许事件触发
willFireEvent:即将触发事件
didFireEvent:已经触发事件
StateMachine
public class StateMachine {
/// Initial state of state machine.
var initialState: State
/// Current state of state machine
public private(set) var currentState : State
/// Available states in state machine
private lazy var availableStates : [State] = []
/// Available events in state machine
private lazy var events : [Event] = []
}
initialState:初始状态
currentState:当前状态
availableStates:所有转换状态
events:所有转换事件
addState
public func addState(state: State) {
availableStates.append(state)
}
/// Add array of states
/// - Parameter states: states array.
public func addStates(states: [State]) {
availableStates.appendContentsOf(states)
}
主要往状态机里添加状态,提供了批量添加addStates。
addEvent
public func addEvent(event: Event) throws {
if event.sourceValues.isEmpty
{
throw EventError.NoSourceValue
}
for state in event.sourceValues
{
if (self.stateWithValue(state) == nil)
{
throw EventError.NoSourceValue
}
}
if (self.stateWithValue(event.destinationValue) == nil) {
throw EventError.NoDestinationValue
}
self.events.append(event)
}
/// Add events to `StateMachine`. This method checks, whether source states and destination state of event are present in `StateMachine`. If not - event will not be added.
/// - Parameter events: events to add to `StateMachine`.
public func addEvents(events: [Event]) {
for event in events
{
guard let _ = try? self.addEvent(event) else {
print("failed adding event with name: %@",event.name)
continue
}
}
}
主要是添加事件。在添加的时候需要做一系列判断,条件成立之后才会添加到eventList中。
event.sourceValues是否为空
event.sourceValues包含的state是否在availableStates中
event.destinationValue是否在availableStates中
fireEvent
public func fireEvent(event: Event) -> Transition {
return _fireEventNamed(event.name)
}
fireEvent内部调用_fireEventNamed方法,返回了Transition,是enum类型,返回转换的结果。
public enum Transition {
/**
Returns whether transition was successful
*/
public var successful: Bool {
switch self {
case .Success(_,_):
return true
case .Error(_):
return false
}
}
/**
Success case with source state, from which transition happened, and destination state, to which state machine switched
*/
case Success(sourceState: State, destinationState: State)
/**
Error case, containing error. Error domain and status codes are described in Errors struct.
*/
case Error(TransitionError)
}
_fireEventNamed
func _fireEventNamed(eventName: String) -> Transition {
if let event = eventWithName(eventName) {
let possibleTransition = possibleTransitionForEvent(event)
switch possibleTransition {
case .Success(let sourceState, let destinationState):
if let shouldBlock = event.shouldFireEvent {
if shouldBlock(event: event) {
event.willFireEvent?(event: event)
activateState(event.destinationValue)
event.didFireEvent?(event: event)
return .Success(sourceState: sourceState, destinationState: destinationState)
}
else {
return .Error(.TransitionDeclined)
}
}
else {
let sourceState = self.currentState
event.willFireEvent?(event: event)
activateState(event.destinationValue)
event.didFireEvent?(event: event)
return .Success(sourceState: sourceState, destinationState: destinationState)
}
default :
return possibleTransition
}
}
else {
return .Error(.UnknownEvent)
}
}
首先判断eventName是否在eventList中存在
possibleTransitionForEvent,判断event的sourceValues是否是包含当前的currentState,若是就返回.Success(srcState, desState)。
判断event.shouldFireEvent,是否可以触发事件。如果设置了shouldFireEvent,则判断可以执行,就如顺序执行willFireEvent-->activateState-->didFireEvent。如果没有设置,还是按willFireEvent-->activateState-->didFireEvent执行。
activiateState
public func activateState(stateValue: T) {
if (isStateAvailable(stateValue))
{
let oldState = currentState
let newState = stateWithValue(stateValue)!
newState.willEnterState?(enteringState: newState)
oldState.willExitState?(exitingState: oldState)
currentState = newState
oldState.didExitState?(exitingState: oldState)
newState.didEnterState?(enteringState: currentState)
}
}
stateWithValue:在availableStates中筛选value=stateValue的state。
依次调用:willEnterState--->willExitState--->didExitState--->didEnterState