Swift StateMachine源码分析

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

  1. event.sourceValues是否为空

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

  3. 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)
        }
    }
  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

你可能感兴趣的:(Swift StateMachine源码分析)