Last active
March 13, 2023 14:59
-
-
Save jemmons/1e7183870a788c62facc to your computer and use it in GitHub Desktop.
A Simple Swift State Machine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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