import Foundation class StateMachine { 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 func didTransitionFrom(from: StateType, to: StateType) } enum Should { case Continue, Abort, Redirect(T) }