Skip to content

Instantly share code, notes, and snippets.

@chourobin
Forked from jemmons/StateMachine.swift
Created November 21, 2016 15:36
Show Gist options
  • Save chourobin/a447e3fa8fe4fdd4dbc19b3cc8e63ddc to your computer and use it in GitHub Desktop.
Save chourobin/a447e3fa8fe4fdd4dbc19b3cc8e63ddc to your computer and use it in GitHub Desktop.
A Simple Swift State Machine
import Foundation
class StateMachine <P: StateMachineDelegateProtocol> {
private unowned let delegate: P
private var _state: P.StateType {
didSet{
delegate.didTransitionFrom(from: oldValue, to: _state)
}
}
var state: P.StateType {
get{
return _state
}
set{
// Can't be an observer because we need the option to CONDITIONALLY set state
delegateTransitionTo(to: newValue)
}
}
init(initialState: P.StateType, delegate: P) {
// Set the primitive to avoid calling the delegate.
_state = initialState
self.delegate = delegate
}
private func delegateTransitionTo(to: P.StateType) {
switch delegate.shouldTransitionFrom(from: _state, to: to) {
case .Continue:
_state = to
case .Redirect(let newState):
_state = to
state = newState
case .Abort:
break;
}
}
}
protocol StateMachineDelegateProtocol: class {
associatedtype StateType
func shouldTransitionFrom(from: StateType, to: StateType) -> Should<StateType>
func didTransitionFrom(from: StateType, to: StateType)
}
enum Should<T> {
case Continue, Abort, Redirect(T)
}
import UIKit
class Example : UIView{
private var machine:StateMachine<Example>!
enum TrafficLight{
case Stop, Go, Caution
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
machine = StateMachine(initialState: .Stop, delegate: self)
}
@IBAction func tappedGo(sender:AnyObject){
machine.state = .Go
}
@IBAction func tappedCaution(sender:AnyObject){
machine.state = .Caution
}
}
extension Example : StateMachineDelegateProtocol{
typealias StateType = TrafficLight
func shouldTransitionFrom(from: StateType, to: StateType) -> Should<StateType> {
switch (from, to){
case (.Stop, .Go), (.Caution, .Stop):
return .Continue
case (.Go, .Caution):
return .Redirect(.Stop)
default:
return .Abort
}
}
func didTransitionFrom(from: StateType, to: StateType) {
switch to{
case .Stop:
backgroundColor = UIColor.redColor()
case .Go:
backgroundColor = UIColor.greenColor()
case .Caution:
backgroundColor = UIColor.yellowColor()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment