@@ -51,6 +51,11 @@ public struct StateMachineSchema<A, B, C>: StateMachineSchemaType {
5151/// `StateMachineSchemaType` documentation for more information about schemas
5252/// and subjects.
5353///
54+ /// References to class-based subjects are weak. This helps to remove
55+ /// subject-machine reference cycles, but it also means you have to keep a
56+ /// strong reference to a subject somewhere else. When subject references
57+ /// become `nil`, transitions are no longer performed.
58+ ///
5459/// The state machine provides the `state` property for inspecting the current
5560/// state and the `handleEvent` method for triggering state transitions
5661/// defined in the schema.
@@ -73,25 +78,49 @@ public final class StateMachine<T: StateMachineSchemaType> {
7378 private let schema : T
7479
7580 /// Object associated with the state machine. Can be accessed in
76- /// transition blocks.
77- private let subject : T . Subject
81+ /// transition blocks. Closure used to allow for weak references.
82+ private let subject : ( ) -> T . Subject ?
7883
79- public init ( schema: T , subject: T . Subject ) {
84+ private init ( schema: T , subject: ( ) -> T . Subject ? ) {
8085 self . state = schema. initialState
8186 self . schema = schema
8287 self . subject = subject
8388 }
8489
8590 /// A method for triggering transitions and changing the state of the
86- /// machine. If the transition logic of the schema defines a transition
91+ /// machine. Transitions are not performed when a weak reference to the subject
92+ /// becomes `nil`. If the transition logic of the schema defines a transition
8793 /// for current state and given event, the state is changed, the optional
8894 /// transition block is executed, and `didTransitionCallback` is called.
8995 public func handleEvent( event: T . Event ) {
90- if let ( newState , transition ) = schema . transitionLogic ( state , event ) {
91- let oldState = state
92- state = newState
93- transition ? ( subject )
94- didTransitionCallback ? ( oldState , event , newState )
96+ guard let
97+ subject = subject ( ) ,
98+ ( newState , transition ) = schema . transitionLogic ( state , event )
99+ else {
100+ return
95101 }
102+
103+ let oldState = state
104+ state = newState
105+
106+ transition ? ( subject)
107+ didTransitionCallback ? ( oldState, event, newState)
108+ }
109+ }
110+
111+
112+ public extension StateMachine where T. Subject: AnyObject {
113+ /// Creates a state machine with a weak reference to a subject. This helps
114+ /// to remove subject-machine reference cycles, but it also means you have
115+ /// to keep a strong reference to a subject somewhere else. When subject
116+ /// reference becomes `nil`, transitions are no longer performed.
117+ public convenience init ( schema: T , subject: T . Subject ) {
118+ self . init ( schema: schema, subject: { [ weak subject] in subject } )
119+ }
120+ }
121+
122+ public extension StateMachine {
123+ public convenience init ( schema: T , subject: T . Subject ) {
124+ self . init ( schema: schema, subject: { subject } )
96125 }
97126}
0 commit comments