[swift-evolution] [Concurrency] modifying beginAsync, suspendAsync to support cancellation
Marc Schlichte
marc.schlichte at googlemail.com
Sat Aug 19 13:33:17 CDT 2017
Hi,
to support cancellation, I propose the following changes to `beginAsync()` and `suspendAsync()`:
`beginAsync()` returns an object adhering to a `Cancelable` protocol:
```
func beginAsync(_ body: () async throws-> Void) rethrows -> Cancelable
protocol Cancelable { func cancel() }
```
`suspendAsync()` takes a new thunk parameter:
```
func suspendAsync<T>(onCancel: () -> Void, body: (cont: (T) -> Void, err: (Error) -> Void) async -> T
```
Now, when `cancel()` is invoked, the `onCancel` thunk in the current suspension (if any) will be called.
Example:
```
var task: Cancelable?
@IBAction func buttonDidClick(sender: AnyObject) {
task = beginAsync {
do {
let image = try await processImage()
imageView.image = image
} catch AsyncError.canceled {
imageView.image = nil // or some fallback image...
} catch {
// other handling
}
}
)
@IBAction func cancelDidClick(sender: AnyObject) {
task?.cancel()
}
func processImage() async throws -> UIImage {
// This processing should be on a background queue (or better an Actor :-) - but ignored for this example
var cancelled = false
suspendAsync(onCancel: {
cancelled = true
}, body: { cont, err in
while !done && !cancelled {
// do the processing on image until done or canceled
}
guard !cancelled else { err(AsyncError.canceled) } // BTW, maybe change signature of `suspendAsync` to allow to throw here instead
cont(image)
}
}
```
Cheers
Marc
More information about the swift-evolution
mailing list