Modern finite-state machine implemented in pure Swift
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
MessagesState.playground improve adding events methods by making them throw. Make canFireEvent… Nov 15, 2015
Plists Releasing version 3.1.0. Mar 14, 2018
Sources Reimplement eventWithName method to make changes backwards compatible. Mar 13, 2018
Tests/TransporterTests `StateMachine` can find event that can be applied given the current s… Mar 7, 2018
Transporter.xcodeproj Update Xcode settings, Travis build configurations, update Changelog. Mar 13, 2018
Turnstile.playground improve adding events methods by making them throw. Make canFireEvent… Nov 15, 2015
fastlane Update Xcode settings, Travis build configurations, update Changelog. Mar 13, 2018
xcconfigs use a single scheme for all platforms Feb 13, 2016
.gitignore Support Swift Package Manager and Linux Jan 8, 2016
.travis.yml Update Xcode settings, Travis build configurations, update Changelog. Mar 13, 2018
CHANGELOG.md Releasing version 3.1.0. Mar 14, 2018
Gemfile migrate to fastlane, add verification for SPM, carthage, framework te… May 28, 2017
Gemfile.lock migrate to fastlane, add verification for SPM, carthage, framework te… May 28, 2017
LICENSE Initial commit Jul 6, 2014
Package.swift Support Swift Package Manager and Linux Jan 8, 2016
README.md Update README.md Nov 14, 2016
Transporter.podspec Releasing version 3.1.0. Mar 14, 2018
codecov.sh migrate to fastlane, add verification for SPM, carthage, framework te… May 28, 2017
codecov.yml Update codecov.yml May 11, 2016

README.md

Build Status   codecov.io CocoaPod platform   CocoaPod version   Carthage compatible Packagist Transporter

Transporter is a modern finite-state machine implemented in pure Swift. It is truly cross-platform, and supports iOS, OS X, tvOS, watchOS, Linux.

Features

  • Simple mode, allowing to manually switch states
  • Strict mode, allowing switching states only with Events and proper Transition
  • Closure(block)-based callbacks on states and events
  • Generic implementation allows using any State values
  • Unit-tested and reliable

Classic turnstile example

enum Turnstile {
    case Locked
    case Unlocked
}

let locked = State(Turnstile.Locked)
let unlocked = State(Turnstile.Unlocked)

locked.didEnterState = { _ in lockEntrance() }
unlocked.didEnterState = { _ in unlockEntrance() }

let coinEvent = Event(name: "Coin", sourceValues: [Turnstile.Locked], destinationValue: Turnstile.Unlocked)
let pushEvent = Event(name: "Push", sourceValues: [Turnstile.Unlocked], destinationValue: Turnstile.Locked)

let turnstile = StateMachine(initialState: locked, states: [unlocked])
turnstile.addEvents([coinEvent,pushEvent])

turnstile.fireEvent("Coin")
turnstile.isInState(.Unlocked) //true

States

Due to generic implementation, you can have StateMachine of any type you want. The only requirement for state values is they should be Hashable. So, you can have Int State, or String State etc. Or have value of enum, like it's shown in example.

let intState = State(0)
let stringState = State("foo")
let enumState = State(Turnstile.Locked)

Getting states

  let state = machine.stateWithValue(4)

Adding states

  machine.addState(state)
  machine.addStates([state1,state2])

You can also use convenience constructor:

  let machine = StateMachine(initialState: initialState, states: [state1,state2])

Events

Adding events implicitly checks, whether event source states and destination state are present in StateMachine. If states are not present, event will not be added to StateMachine.

  _ = try? machine.addEvent(event)
  machine.addEvents([event1,event2])

Can event be fired?

  if machine.canFireEvent("foo") {
    println("Fire it!")
  }

Transitions

When event is fired, StateMachine returns Transition object, that you can react to

  let transition = machine.fireEvent("Coin")
  switch transition {
  case .Success(let sourceState, let destinationState):
    println("Successful transition from state: \(sourceState) to state: \(destinationState)")
  case .Error(let error)
    println("Failed to transition with error: \(error)")
  }

Switching states manually

Transporter supports canonic finite state machine principle, that disallows transitions, if they are not defined in events StateMachine has, but sometimes you would want something simpler. Transporter gives you ability to switch states manually without actually creating any events.

  let initial = State("Initial")
  let machine = StateMachine(initialState: initial)
  machine.addState(State("Finished"))

  machine.activateState("Finished")
  machine.isInState("Finished") // true

Objective-C

Due to generic implementation of Transporter, it will not support Objective-C. If you are looking for state machine, written in Objective-C, i recommend great TransitionKit library by Blake Watters.

Requirements

  • iOS 8
  • Mac OS 10.10
  • watchOS 2
  • tvOS 9.0
  • Swift 3
  • XCode 8

Installation

CocoaPods

  pod 'Transporter', '~> 3.0.0'

Carthage

  carthage 'DenHeadless/Transporter' "3.0.0"