@@ -9,14 +9,14 @@ import ReactiveSwift
9
9
public final class Store < State, Action> {
10
10
@MutableProperty
11
11
private( set) var state : State
12
-
12
+
13
13
private var isSending = false
14
14
private let reducer : ( inout State , Action ) -> Effect < Action , Never >
15
15
private var synchronousActionsToSend : [ Action ] = [ ]
16
16
private var bufferedActions : [ Action ] = [ ]
17
17
internal var effectDisposables : [ UUID : Disposable ] = [ : ]
18
18
internal var parentDisposable : Disposable ?
19
-
19
+
20
20
/// Initializes a store from an initial state, a reducer, and an environment.
21
21
///
22
22
/// - Parameters:
@@ -33,7 +33,7 @@ public final class Store<State, Action> {
33
33
reducer: { reducer. run ( & $0, $1, environment) }
34
34
)
35
35
}
36
-
36
+
37
37
/// Scopes the store to one that exposes local state and actions.
38
38
///
39
39
/// This can be useful for deriving new stores to hand to child views in an application. For
@@ -179,7 +179,7 @@ public final class Store<State, Action> {
179
179
}
180
180
return localStore
181
181
}
182
-
182
+
183
183
/// Scopes the store to one that exposes local state.
184
184
///
185
185
/// - Parameter toLocalState: A function that transforms `State` into `LocalState`.
@@ -189,7 +189,7 @@ public final class Store<State, Action> {
189
189
) -> Store < LocalState , Action > {
190
190
self . scope ( state: toLocalState, action: { $0 } )
191
191
}
192
-
192
+
193
193
/// Scopes the store to a producer of stores of more local state and local actions.
194
194
///
195
195
/// - Parameters:
@@ -201,14 +201,14 @@ public final class Store<State, Action> {
201
201
state toLocalState: @escaping ( Effect < State , Never > ) -> Effect < LocalState , Never > ,
202
202
action fromLocalAction: @escaping ( LocalAction ) -> Action
203
203
) -> Effect < Store < LocalState , LocalAction > , Never > {
204
-
204
+
205
205
func extractLocalState( _ state: State ) -> LocalState ? {
206
206
var localState : LocalState ?
207
207
_ = toLocalState ( Effect ( value: state) )
208
208
. startWithValues { localState = $0 }
209
209
return localState
210
210
}
211
-
211
+
212
212
return toLocalState ( self . $state. producer)
213
213
. map { localState in
214
214
let localStore = Store < LocalState , LocalAction > (
@@ -219,16 +219,14 @@ public final class Store<State, Action> {
219
219
return . none
220
220
}
221
221
)
222
-
223
- localStore. parentDisposable = self . $state. producer. startWithValues {
224
- [ weak localStore] state in
222
+ localStore. parentDisposable = self . $state. producer. startWithValues { [ weak localStore] state in
225
223
guard let localStore = localStore else { return }
226
224
localStore. state = extractLocalState ( state) ?? localStore. state
227
225
}
228
226
return localStore
229
227
}
230
228
}
231
-
229
+
232
230
/// Scopes the store to a producer of stores of more local state and local actions.
233
231
///
234
232
/// - Parameter toLocalState: A function that transforms a producer of `State` into a producer
@@ -240,30 +238,29 @@ public final class Store<State, Action> {
240
238
) -> Effect < Store < LocalState , Action > , Never > {
241
239
self . producerScope ( state: toLocalState, action: { $0 } )
242
240
}
243
-
241
+
244
242
func send( _ action: Action ) {
245
243
if !self . isSending {
246
244
self . synchronousActionsToSend. append ( action)
247
245
} else {
248
246
self . bufferedActions. append ( action)
249
247
return
250
248
}
251
-
249
+
252
250
while !self . synchronousActionsToSend. isEmpty || !self . bufferedActions. isEmpty {
253
251
let action =
254
252
!self . synchronousActionsToSend. isEmpty
255
253
? self . synchronousActionsToSend. removeFirst ( )
256
254
: self . bufferedActions. removeFirst ( )
257
-
255
+
258
256
self . isSending = true
259
257
let effect = self . reducer ( & self . state, action)
260
258
self . isSending = false
261
-
259
+
262
260
var didComplete = false
263
261
let effectID = UUID ( )
264
262
265
263
var isProcessingEffects = true
266
-
267
264
let observer = Signal < Action , Never > . Observer (
268
265
value: { [ weak self] action in
269
266
if isProcessingEffects {
@@ -284,34 +281,34 @@ public final class Store<State, Action> {
284
281
)
285
282
let effectDisposable = effect. start ( observer)
286
283
isProcessingEffects = false
287
-
284
+
288
285
if !didComplete {
289
286
self . effectDisposables [ effectID] = effectDisposable
290
287
} else {
291
288
effectDisposable. dispose ( )
292
289
}
293
290
}
294
291
}
295
-
292
+
296
293
/// Returns a "stateless" store by erasing state to `Void`.
297
294
public var stateless : Store < Void , Action > {
298
295
self . scope ( state: { _ in ( ) } )
299
296
}
300
-
297
+
301
298
/// Returns an "actionless" store by erasing action to `Never`.
302
299
public var actionless : Store < State , Never > {
303
300
func absurd< A> ( _ never: Never ) -> A { }
304
301
return self . scope ( state: { $0 } , action: absurd)
305
302
}
306
-
303
+
307
304
private init (
308
305
initialState: State ,
309
306
reducer: @escaping ( inout State , Action ) -> Effect < Action , Never >
310
307
) {
311
308
self . reducer = reducer
312
309
self . state = initialState
313
310
}
314
-
311
+
315
312
deinit {
316
313
self . parentDisposable? . dispose ( )
317
314
self . effectDisposables. keys. forEach { id in
@@ -323,24 +320,44 @@ public final class Store<State, Action> {
323
320
/// A producer of store state.
324
321
@dynamicMemberLookup
325
322
public struct Produced < Value> : SignalProducerConvertible {
326
- public let producer : Effect < Value , Never >
327
-
328
- init ( by upstream: Effect < Value , Never > ) {
329
- self . producer = upstream
323
+ private let _producer : Effect < Value , Never >
324
+ private let comparator : ( Value , Value ) -> Bool
325
+
326
+ public var producer : Effect < Value , Never > {
327
+ _producer. skipRepeats ( comparator)
330
328
}
331
-
329
+
330
+ init (
331
+ by upstream: Effect < Value , Never > ,
332
+ isEqual: @escaping ( Value , Value ) -> Bool
333
+ ) {
334
+ self . _producer = upstream
335
+ self . comparator = isEqual
336
+ }
337
+
338
+ init ( by upstream: Effect < Value , Never > ) where Value: Equatable {
339
+ self . init ( by: upstream, isEqual: == )
340
+ }
341
+
332
342
/// Returns the resulting producer of a given key path.
333
343
public subscript< LocalValue> (
334
344
dynamicMember keyPath: KeyPath < Value , LocalValue >
335
345
) -> Effect < LocalValue , Never > where LocalValue: Equatable {
336
346
self . producer. map ( keyPath) . skipRepeats ( )
337
347
}
348
+
349
+ /// Returns the resulting producer of a given key path.
350
+ public subscript< LocalValue> (
351
+ dynamicMember keyPath: KeyPath < Value , LocalValue >
352
+ ) -> Produced < LocalValue > where LocalValue: Equatable {
353
+ Produced < LocalValue > ( by: self . producer. map ( keyPath) . skipRepeats ( ) )
354
+ }
338
355
}
339
356
340
357
@available (
341
- * , deprecated,
342
- message:
343
- """
358
+ * , deprecated,
359
+ message:
360
+ """
344
361
Consider using `Produced<State>` instead, this typealias is added for backward compatibility and will be removed in the next major release.
345
362
"""
346
363
)
0 commit comments