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

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to