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()
}
Just adding here that instead of directly using the low-level beginAsync, a Future/Promise could be used instead:
var task: Future<UIImage>?
@IBAction func buttonDidClick\(sender: AnyObject\) \{
task = Future \{
try await processImage\(\)
\}
do \{
imageView\.image = try await task\!\.get\(\)
\} catch AsyncError\.canceled \{
imageView\.image = nil // or some fallback image\.\.\.
\} catch \{
// other handling
\}
\}
@iBAction func cancelDidClick\(sender: AnyObject\) \{
task?\.cancel\(\)
\}
Of course, the init of Future would have to be changed
convenience init(_ body: () throws async -> T) {
self.init()
task = beginAsync {
do {
self.fulfill(try await body())
} catch {
self.fail(error)
}
}
}
(BTW also added missing throws and try in code above)
and cancel() would have to be added to Future:
public func cancel\(\) \{
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)
}
}
^ BTW, this should be `return await suspendAsync(…`
···
Am 19.08.2017 um 20:33 schrieb Marc Schlichte via swift-evolution <swift-evolution@swift.org>:
Cheers
Marc
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution