@@ -109,9 +109,10 @@ import SwiftUI
109
109
extension ViewStore {
110
110
/// Sends an action into the store and then suspends while a piece of state is `true`.
111
111
///
112
- /// This method can be used to interact with async/await code, allowing you to suspend while work
113
- /// is being performed in an effect. One common example of this is using SwiftUI's `.refreshable`
114
- /// method, which shows a loading indicator on the screen while work is being performed.
112
+ /// This method can be used to interact with async/await code, allowing you to suspend while
113
+ /// work is being performed in an effect. One common example of this is using SwiftUI's
114
+ /// `.refreshable` method, which shows a loading indicator on the screen while work is being
115
+ /// performed.
115
116
///
116
117
/// For example, suppose we wanted to load some data from the network when a pull-to-refresh
117
118
/// gesture is performed on a list. The domain and logic for this feature can be modeled like so:
@@ -173,17 +174,19 @@ import SwiftUI
173
174
///
174
175
/// Here we've used the ``send(_:while:)`` method to suspend while the `isLoading` state is
175
176
/// `true`. Once that piece of state flips back to `false` the method will resume, signaling to
176
- /// `.refreshable` that the work has finished which will cause the loading indicator to disappear.
177
+ /// `.refreshable` that the work has finished which will cause the loading indicator to
178
+ /// disappear.
177
179
///
178
180
/// **Note:** ``ViewStore`` is not thread safe and you should only send actions to it from the
179
- /// main thread. If you are wanting to send actions on background threads due to the fact that the
180
- /// reducer is performing computationally expensive work, then a better way to handle this is to
181
- /// wrap that work in an ``Effect`` that is performed on a background thread so that the result
182
- /// can be fed back into the store.
181
+ /// main thread. If you are wanting to send actions on background threads due to the fact that
182
+ /// the reducer is performing computationally expensive work, then a better way to handle this
183
+ /// is to wrap that work in an ``Effect`` that is performed on a background thread so that the
184
+ /// result can be fed back into the store.
183
185
///
184
186
/// - Parameters:
185
187
/// - action: An action.
186
- /// - predicate: A predicate on `State` that determines for how long this method should suspend.
188
+ /// - predicate: A predicate on `State` that determines for how long this method should
189
+ /// suspend.
187
190
public func send(
188
191
_ action: Action ,
189
192
while predicate: @escaping ( State ) -> Bool
@@ -199,7 +202,8 @@ import SwiftUI
199
202
/// - Parameters:
200
203
/// - action: An action.
201
204
/// - animation: The animation to perform when the action is sent.
202
- /// - predicate: A predicate on `State` that determines for how long this method should suspend.
205
+ /// - predicate: A predicate on `State` that determines for how long this method should
206
+ /// suspend.
203
207
public func send(
204
208
_ action: Action ,
205
209
animation: Animation ? ,
@@ -211,20 +215,20 @@ import SwiftUI
211
215
212
216
/// Suspends while a predicate on state is `true`.
213
217
///
214
- /// - Parameter predicate: A predicate on `State` that determines for how long this method should
215
- /// suspend.
218
+ /// - Parameter predicate: A predicate on `State` that determines for how long this method
219
+ /// should suspend.
216
220
public func suspend( while predicate: @escaping ( State ) -> Bool ) async {
217
- var cancellable : Disposable ?
221
+ let cancellable = Box < Disposable ? > ( wrappedValue : nil )
218
222
try ? await withTaskCancellationHandler (
219
- handler: { [ cancellable] in cancellable ? . dispose ( ) } ,
223
+ handler: { cancellable. wrappedValue ? . dispose ( ) } ,
220
224
operation: {
221
225
try Task . checkCancellation ( )
222
226
try await withUnsafeThrowingContinuation { ( continuation: UnsafeContinuation < Void , Error > ) in
223
227
guard !Task. isCancelled else {
224
228
continuation. resume ( throwing: CancellationError ( ) )
225
229
return
226
230
}
227
- cancellable = self . produced. producer
231
+ cancellable. wrappedValue = self . produced. producer
228
232
. filter { !predicate( $0) }
229
233
. take ( first: 1 )
230
234
. startWithValues { _ in
@@ -236,4 +240,12 @@ import SwiftUI
236
240
)
237
241
}
238
242
}
243
+
244
+ private class Box < Value> {
245
+ var wrappedValue : Value
246
+
247
+ init ( wrappedValue: Value ) {
248
+ self . wrappedValue = wrappedValue
249
+ }
250
+ }
239
251
#endif
0 commit comments