@@ -2,42 +2,44 @@ import Dispatch
22import Foundation
33import Result
44
5- /// Represents an action that will do some work when executed with a value of
6- /// type `Input`, then return zero or more values of type `Output` and/or fail
7- /// with an error of type `Error`. If no failure should be possible, NoError can
8- /// be specified for the `Error` parameter.
5+ /// `Action` represents a repeatable work with varying input and state that may output
6+ /// zero or more values, or fail with an error at some point.
97///
10- /// Actions enforce serial execution. Any attempt to execute an action multiple
11- /// times concurrently will return an error.
8+ /// The core of `Action` is the `workProducer` closure that is supplied to the
9+ /// initializer. For every execution attempt with a varying input, if the `Action` is
10+ /// enabled, it would invoke `workProducer` with the latest state and the input to obtain
11+ /// a customized unit of work — represented by a `SignalProducer`.
12+ ///
13+ /// `Action` enforces serial execution, and disables the `Action` during the execution.
1214public final class Action < Input, Output, Error: Swift . Error > {
1315 private let deinitToken : Lifetime . Token
1416
1517 private let executeClosure : ( _ state: Any , _ input: Input ) -> SignalProducer < Output , Error >
1618 private let eventsObserver : Signal < Event < Output , Error > , NoError > . Observer
1719 private let disabledErrorsObserver : Signal < ( ) , NoError > . Observer
1820
19- /// The lifetime of the Action.
21+ /// The lifetime of the ` Action` .
2022 public let lifetime : Lifetime
2123
22- /// A signal of all events generated from applications of the Action.
24+ /// A signal of all events generated from all units of work of the ` Action` .
2325 ///
24- /// In other words, this will send every `Event` from every signal generated
25- /// by each SignalProducer returned from apply() except `ActionError.disabled` .
26+ /// In other words, this sends every `Event` from every unit of work that the `Action`
27+ /// executes .
2628 public let events : Signal < Event < Output , Error > , NoError >
2729
28- /// A signal of all values generated from applications of the Action.
30+ /// A signal of all values generated from all units of work of the ` Action` .
2931 ///
30- /// In other words, this will send every value from every signal generated
31- /// by each SignalProducer returned from apply() except `ActionError.disabled` .
32+ /// In other words, this sends every value from every unit of work that the `Action`
33+ /// executes .
3234 public let values : Signal < Output , NoError >
3335
34- /// A signal of all errors generated from applications of the Action.
36+ /// A signal of all errors generated from all units of work of the ` Action` .
3537 ///
36- /// In other words, this will send errors from every signal generated by
37- /// each SignalProducer returned from apply() except `ActionError.disabled` .
38+ /// In other words, this sends every error from every unit of work that the `Action`
39+ /// executes .
3840 public let errors : Signal < Error , NoError >
3941
40- /// A signal which is triggered by `ActionError.disabled `.
42+ /// A signal of all failed attempts to start a unit of work of the `Action `.
4143 public let disabledErrors : Signal < ( ) , NoError >
4244
4345 /// A signal of all completed events generated from applications of the action.
@@ -54,9 +56,12 @@ public final class Action<Input, Output, Error: Swift.Error> {
5456
5557 private let state : MutableProperty < ActionState >
5658
57- /// Initializes an action that will be conditionally enabled based on the
58- /// value of `state`. Creates a `SignalProducer` for each input and the
59- /// current value of `state`.
59+ /// Initializes an `Action` that would be conditionally enabled depending on its
60+ /// state.
61+ ///
62+ /// When the `Action` is asked to start the execution with an input value, a unit of
63+ /// work — represented by a `SignalProducer` — would be created by invoking
64+ /// `workProducer` with the latest state and the input value.
6065 ///
6166 /// - note: `Action` guarantees that changes to `state` are observed in a
6267 /// thread-safe way. Thus, the value passed to `isEnabled` will
@@ -68,21 +73,19 @@ public final class Action<Input, Output, Error: Swift.Error> {
6873 /// The various convenience initializers should cover most use cases.
6974 ///
7075 /// - parameters:
71- /// - state: A property that provides the current state of the action
72- /// whenever `apply()` is called.
73- /// - enabledIf: A predicate that, given the current value of `state`,
74- /// returns whether the action should be enabled.
75- /// - execute: A closure that returns the `SignalProducer` returned by
76- /// calling `apply(Input)` on the action, optionally using
77- /// the current value of `state`.
78- public init < State: PropertyProtocol > ( state property: State , enabledIf isEnabled: @escaping ( State . Value ) -> Bool , _ execute: @escaping ( State . Value , Input ) -> SignalProducer < Output , Error > ) {
76+ /// - state: A property to be the state of the `Action`.
77+ /// - enabledIf: A predicate which determines the availability of the `Action`,
78+ /// given the latest `Action` state.
79+ /// - workProducer: A closure that produces a unit of work, as `SignalProducer`, to
80+ /// be executed by the `Action`.
81+ public init < State: PropertyProtocol > ( state property: State , enabledIf isEnabled: @escaping ( State . Value ) -> Bool , _ workProducer: @escaping ( State . Value , Input ) -> SignalProducer < Output , Error > ) {
7982 deinitToken = Lifetime . Token ( )
8083 lifetime = Lifetime ( deinitToken)
8184
8285 // Retain the `property` for the created `Action`.
8386 lifetime. observeEnded { _ = property }
8487
85- executeClosure = { state, input in execute ( state as! State . Value , input) }
88+ executeClosure = { state, input in workProducer ( state as! State . Value , input) }
8689
8790 ( events, eventsObserver) = Signal < Event < Output , Error > , NoError > . pipe ( )
8891 ( disabledErrors, disabledErrorsObserver) = Signal < ( ) , NoError > . pipe ( )
@@ -106,46 +109,52 @@ public final class Action<Input, Output, Error: Swift.Error> {
106109 self . isExecuting = state. map { $0. isExecuting } . skipRepeats ( )
107110 }
108111
109- /// Initializes an action that will be conditionally enabled, and creates a
110- /// `SignalProducer` for each input.
112+ /// Initializes an `Action` that would be conditionally enabled.
113+ ///
114+ /// When the `Action` is asked to start the execution with an input value, a unit of
115+ /// work — represented by a `SignalProducer` — would be created by invoking
116+ /// `workProducer` with the input value.
111117 ///
112118 /// - parameters:
113- /// - enabledIf: Boolean property that shows whether the action is
114- /// enabled.
115- /// - execute: A closure that returns the signal producer returned by
116- /// calling `apply(Input)` on the action.
117- public convenience init < P: PropertyProtocol > ( enabledIf property: P , _ execute: @escaping ( Input ) -> SignalProducer < Output , Error > ) where P. Value == Bool {
119+ /// - enabledIf: A property which determines the availability of the `Action`.
120+ /// - workProducer: A closure that produces a unit of work, as `SignalProducer`, to
121+ /// be executed by the `Action`.
122+ public convenience init < P: PropertyProtocol > ( enabledIf property: P , _ workProducer: @escaping ( Input ) -> SignalProducer < Output , Error > ) where P. Value == Bool {
118123 self . init ( state: property, enabledIf: { $0 } ) { _, input in
119- execute ( input)
124+ workProducer ( input)
120125 }
121126 }
122127
123- /// Initializes an action that will be enabled by default, and creates a
124- /// SignalProducer for each input.
128+ /// Initializes an `Action` that would always be enabled.
129+ ///
130+ /// When the `Action` is asked to start the execution with an input value, a unit of
131+ /// work — represented by a `SignalProducer` — would be created by invoking
132+ /// `workProducer` with the input value.
125133 ///
126134 /// - parameters:
127- /// - execute : A closure that returns the signal producer returned by
128- /// calling `apply(Input)` on the action .
129- public convenience init ( _ execute : @escaping ( Input ) -> SignalProducer < Output , Error > ) {
130- self . init ( enabledIf: Property ( value: true ) , execute )
135+ /// - workProducer : A closure that produces a unit of work, as `SignalProducer`, to
136+ /// be executed by the `Action` .
137+ public convenience init ( _ workProducer : @escaping ( Input ) -> SignalProducer < Output , Error > ) {
138+ self . init ( enabledIf: Property ( value: true ) , workProducer )
131139 }
132140
133141 deinit {
134142 eventsObserver. sendCompleted ( )
135143 disabledErrorsObserver. sendCompleted ( )
136144 }
137145
138- /// Creates a SignalProducer that, when started, will execute the action
139- /// with the given input, then forward the results upon the produced Signal.
146+ /// Create a `SignalProducer` that would attempt to create and start a unit of work of
147+ /// the `Action`. The `SignalProducer` would forward only events generated by the unit
148+ /// of work it created.
140149 ///
141- /// - note: If the action is disabled when the returned SignalProducer is
142- /// started, the produced signal will send `ActionError.disabled`,
143- /// and nothing will be sent upon `values` or `errors` for that
144- /// particular signal.
150+ /// If the execution attempt is failed, the producer would fail with
151+ /// `ActionError.disabled`.
145152 ///
146153 /// - parameters:
147- /// - input: A value that will be passed to the closure creating the signal
148- /// producer.
154+ /// - input: A value to be used to create the unit of work.
155+ ///
156+ /// - returns: A producer that forwards events generated by its started unit of work,
157+ /// or emits `ActionError.disabled` if the execution attempt is failed.
149158 public func apply( _ input: Input ) -> SignalProducer < Output , ActionError < Error > > {
150159 return SignalProducer { observer, disposable in
151160 let startingState = self . state. modify { state -> Any ? in
@@ -213,43 +222,47 @@ extension Action: BindingTargetProvider {
213222}
214223
215224extension Action where Input == Void {
216- /// Initializes an action that uses an `Optional` property for its input,
217- /// and is disabled whenever the input is `nil`. When executed, a `SignalProducer`
218- /// is created with the current value of the input.
225+ /// Initializes an `Action` that uses a property of optional as its state.
226+ ///
227+ /// When the `Action` is asked to start the execution, a unit of work — represented by
228+ /// a `SignalProducer` — would be created by invoking `workProducer` with the latest
229+ /// value of the state.
230+ ///
231+ /// If the property holds a `nil`, the `Action` would be disabled until it is not
232+ /// `nil`.
219233 ///
220234 /// - parameters:
221- /// - input: An `Optional` property whose current value is used as input
222- /// whenever the action is executed. The action is disabled
223- /// whenever the value is `nil`.
224- /// - execute: A closure to return a new `SignalProducer` based on the
225- /// current value of `input`.
226- public convenience init < P: PropertyProtocol , T> ( input: P , _ execute: @escaping ( T ) -> SignalProducer < Output , Error > ) where P. Value == T ? {
227- self . init ( state: input, enabledIf: { $0 != nil } ) { input, _ in
228- execute ( input!)
235+ /// - state: A property of optional to be the state of the `Action`.
236+ /// - workProducer: A closure that produces a unit of work, as `SignalProducer`, to
237+ /// be executed by the `Action`.
238+ public convenience init < P: PropertyProtocol , T> ( state: P , _ workProducer: @escaping ( T ) -> SignalProducer < Output , Error > ) where P. Value == T ? {
239+ self . init ( state: state, enabledIf: { $0 != nil } ) { state, _ in
240+ workProducer ( state!)
229241 }
230242 }
231243
232- /// Initializes an action that uses a property for its input. When executed,
233- /// a `SignalProducer` is created with the current value of the input.
244+ /// Initializes an `Action` that uses a property as its state.
245+ ///
246+ /// When the `Action` is asked to start the execution, a unit of work — represented by
247+ /// a `SignalProducer` — would be created by invoking `workProducer` with the latest
248+ /// value of the state.
234249 ///
235250 /// - parameters:
236- /// - input: A property whose current value is used as input
237- /// whenever the action is executed.
238- /// - execute: A closure to return a new `SignalProducer` based on the
239- /// current value of `input`.
240- public convenience init < P: PropertyProtocol , T> ( input: P , _ execute: @escaping ( T ) -> SignalProducer < Output , Error > ) where P. Value == T {
241- self . init ( input: input. map ( Optional . some) , execute)
251+ /// - state: A property to be the state of the `Action`.
252+ /// - workProducer: A closure that produces a unit of work, as `SignalProducer`, to
253+ /// be executed by the `Action`.
254+ public convenience init < P: PropertyProtocol , T> ( state: P , _ workProducer: @escaping ( T ) -> SignalProducer < Output , Error > ) where P. Value == T {
255+ self . init ( state: state. map ( Optional . some) , workProducer)
242256 }
243257}
244258
245- /// The type of error that can occur from Action.apply, where `Error` is the
246- /// type of error that can be generated by the specific Action instance .
259+ /// `ActionError` represents the error that could be emitted by a unit of work of a
260+ /// certain ` Action` .
247261public enum ActionError < Error: Swift . Error > : Swift . Error {
248- /// The producer returned from apply() was started while the Action was
249- /// disabled.
262+ /// The execution attempt was failed, since the `Action` was disabled.
250263 case disabled
251264
252- /// The producer returned from apply() sent the given error.
265+ /// The unit of work emitted an error.
253266 case producerFailed( Error )
254267}
255268
0 commit comments