@@ -52,31 +52,51 @@ extension FeedbackLoop {
52
52
public struct Feedback {
53
53
let events : ( _ state: SignalProducer < State , Never > , _ output: FeedbackEventConsumer < Event > ) -> Disposable
54
54
55
- public init (
56
- events: @escaping (
57
- _ state: SignalProducer < State , Never > ,
58
- _ output: FeedbackEventConsumer < Event >
59
- ) -> Disposable
55
+ /// Private designated initializer. See the public designated initializer below.
56
+ fileprivate init (
57
+ startWith events: @escaping ( _ state: SignalProducer < State , Never > , _ output: FeedbackEventConsumer < Event > ) -> Disposable
60
58
) {
61
59
self . events = events
62
60
}
63
61
64
62
/// Creates a custom Feedback, with the complete liberty of defining the data flow.
65
63
///
66
- /// - important: While you may respond to state changes in whatever ways you prefer, you **must** enqueue produced
67
- /// events using the `SignalProducer.enqueue(to:)` operator to the `FeedbackEventConsumer` provided
68
- /// to you. Otherwise, the feedback loop will not be able to pick up and process your events.
64
+ /// Consider using the standard `Feedback` variants, before deriving down to use this desginated initializer.
65
+ ///
66
+ /// Events must be explicitly enqueued using `SignalProducer.enqueue(to:)` with the `FeedbackEventConsumer`
67
+ /// provided to the setup closure. `enqueue(to:)` respects producer cancellation and removes outstanding events
68
+ /// from the loop internal event queue.
69
+ ///
70
+ /// This is useful if you wish to discard events when the state changes in certain ways. For example,
71
+ /// `Feedback(skippingRepeated:effects:)` enqueues events inside `flatMap(.latest)`, so that unprocessed events
72
+ /// are automatically removed when the inner producer has switched.
73
+ ///
74
+ /// - important: The `state` producer provided to the setup closure **does not** replay the current state.
69
75
///
70
76
/// - parameters:
71
77
/// - setup: The setup closure to construct a data flow producing events in respond to changes from `state`,
72
78
/// and having them consumed by `output` using the `SignalProducer.enqueue(to:)` operator.
73
- public static func custom (
74
- _ setup : @escaping (
79
+ public init (
80
+ events : @escaping (
75
81
_ state: SignalProducer < State , Never > ,
76
82
_ output: FeedbackEventConsumer < Event >
77
- ) -> Disposable
78
- ) -> Feedback {
79
- return Feedback ( events: setup)
83
+ ) -> SignalProducer < Never , Never >
84
+ ) {
85
+ self . events = { events ( $0, $1) . start ( ) }
86
+ }
87
+
88
+ /// Creates a Feedback that observes an external producer and maps it to an event.
89
+ ///
90
+ /// - parameters:
91
+ /// - setup: The setup closure to construct a data flow producing events in respond to changes from `state`,
92
+ /// and having them consumed by `output` using the `SignalProducer.enqueue(to:)` operator.
93
+ public init < Values: SignalProducerConvertible > (
94
+ source: Values ,
95
+ as transform: @escaping ( Values . Value ) -> Event
96
+ ) where Values. Error == Never {
97
+ self . init { _, output in
98
+ source. producer. map ( transform) . enqueueNonCancelling ( to: output)
99
+ }
80
100
}
81
101
82
102
/// Creates a Feedback which re-evaluates the given effect every time the
@@ -181,9 +201,7 @@ extension FeedbackLoop {
181
201
182
202
public static var input : ( feedback: Feedback , observer: ( Event ) -> Void ) {
183
203
let pipe = Signal < Event , Never > . pipe ( )
184
- let feedback = Feedback . custom { ( state, consumer) -> Disposable in
185
- pipe. output. producer. enqueue ( to: consumer) . start ( )
186
- }
204
+ let feedback = Feedback ( source: pipe. output, as: { $0 } )
187
205
return ( feedback, pipe. input. send)
188
206
}
189
207
@@ -192,23 +210,45 @@ extension FeedbackLoop {
192
210
value: KeyPath < State , LocalState > ,
193
211
event: @escaping ( LocalEvent ) -> Event
194
212
) -> Feedback {
195
- return Feedback . custom { ( state, consumer) -> Disposable in
213
+ return Feedback ( startWith : { ( state, consumer) in
196
214
return feedback. events (
197
215
state. map ( value) ,
198
216
consumer. pullback ( event)
199
217
)
200
- }
218
+ } )
201
219
}
202
220
203
221
public static func combine( _ feedbacks: FeedbackLoop < State , Event > . Feedback ... ) -> Feedback {
204
- return . custom { ( state, consumer) -> Disposable in
222
+ return Feedback ( startWith : { ( state, consumer) in
205
223
return feedbacks. map { ( feedback) in
206
224
feedback. events ( state, consumer)
207
225
}
208
226
. reduce ( into: CompositeDisposable ( ) ) { ( composite, disposable) in
209
227
composite += disposable
210
228
}
211
- }
229
+ } )
212
230
}
213
231
}
214
232
}
233
+
234
+ extension FeedbackLoop . Feedback {
235
+ @available ( * , deprecated, renamed: " init(_:) " )
236
+ public static func custom(
237
+ _ setup: @escaping (
238
+ _ state: SignalProducer < State , Never > ,
239
+ _ output: FeedbackEventConsumer < Event >
240
+ ) -> Disposable
241
+ ) -> FeedbackLoop . Feedback {
242
+ return FeedbackLoop . Feedback ( events: setup)
243
+ }
244
+
245
+ @available ( * , deprecated, renamed: " init(_:) " )
246
+ public init (
247
+ events: @escaping (
248
+ _ state: SignalProducer < State , Never > ,
249
+ _ output: FeedbackEventConsumer < Event >
250
+ ) -> Disposable
251
+ ) {
252
+ self . events = { events ( $0. producer, $1) }
253
+ }
254
+ }
0 commit comments