Swift StateMachine源码分析

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中。

  1. event.sourceValues是否为空

  2. event.sourceValues包含的state是否在availableStates中

  3. 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)
        }
    }
  1. 首先判断eventName是否在eventList中存在

  2. possibleTransitionForEvent,判断event的sourceValues是否是包含当前的currentState,若是就返回.Success(srcState, desState)。

  3. 判断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
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值