您的位置:首页 > 移动开发 > Swift

Swift StateMachine源码分析

2016-04-10 01:05 666 查看

Swift StateMachine源码分析

状态机的描述如下图:



3@2x.png

swift的StateMachine的源码是Transporter。比较简单,只有3个文件。

Event指事件,State指状态,StateMachine是状态机控制中心。



1@2x.png

State

public class State <T:Hashable>  {

/// Value of state
public let value : T

/// Closure, that will be executed, before state machine enters this state
public var willEnterState: ( (enteringState : State<T> ) -> Void)?

/// Closure, that will be executed, after state machine enters this state
public var didEnterState:  ( (enteringState : State<T> ) -> Void)?

/// Closure, that will be executed before state machine will switch from current state to another state.
public var willExitState:  ( (exitingState  : State<T> ) -> Void)?

/// Closure, that will be executed after state machine switched from current state to another state.
public var didExitState:   ( (exitingState  : State<T> ) -> 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<T:Hashable> {

/// 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:已经触发事件



2@2x.png

StateMachine

public class StateMachine<T:Hashable> {

/// Initial state of state machine.
var initialState: State<T>

/// Current state of state machine
public private(set) var currentState : State<T>

/// Available states in state machine
private lazy var availableStates : [State<T>] = []

/// Available events in state machine
private lazy var events : [Event<T>] = []
}

initialState:初始状态

currentState:当前状态

availableStates:所有转换状态

events:所有转换事件

addState
public func addState(state: State<T>) {
availableStates.append(state)
}

/// Add array of states
/// - Parameter states: states array.
public func addStates(states: [State<T>]) {
availableStates.appendContentsOf(states)
}

主要往状态机里添加状态,提供了批量添加addStates。

addEvent
public func addEvent(event: Event<T>) 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<T>]) {
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<T>) -> Transition<T> {
return _fireEventNamed(event.name)
}

fireEvent内部调用_fireEventNamed方法,返回了Transition,是enum类型,返回转换的结果。

public enum Transition<T:Hashable> {

/**
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<T>, destinationState: State<T>)

/**
Error case, containing error. Error domain and status codes are described in Errors struct.
*/
case Error(TransitionError)
}

_fireEventNamed

func _fireEventNamed(eventName: String) -> Transition<T> {
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

文/summer_liu(简书作者)

原文链接:http://www.jianshu.com/p/85c8c3cc4917

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: