Skip to content

Instantly share code, notes, and snippets.

@jemmons
Last active March 13, 2023 14:59
Show Gist options
  • Save jemmons/1e7183870a788c62facc to your computer and use it in GitHub Desktop.
Save jemmons/1e7183870a788c62facc 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(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(newValue)
}
}
init(initialState:P.StateType, delegate:P){
_state = initialState //set the primitive to avoid calling the delegate.
self.delegate = delegate
}
private func delegateTransitionTo(to:P.StateType){
switch delegate.shouldTransitionFrom(_state, to:to){
case .Continue:
_state = to
case .Redirect(let newState):
_state = to
state = newState
case .Abort:
break;
}
}
}
protocol StateMachineDelegateProtocol: class{
typealias 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