I've read async/await proposal, and I'm thrilled by the possibilities. Here's
what I consider the canonical example:
@IBAction func buttonDidClick(sender:AnyObject) {
beginAsync {
let image = await processImage()
imageView.image = image
}
}
This is exactly the kind of thing I will use async/await for!
But while this example looks extremely elegant, it would suffer from a number
of problems in practice:
1. There is no guarantee that you are on the main thread after `await
processImage()`
2. There is no way to cancel processing
3. Race Condition: If you click the button a second time before
`processImage()` is done, two copies will run simultaneously and you don't know
which image will "win".
So I wondered: What would a more thorough example look like in practice? How
would I fix all these issues?
After some consideration, I came up with the following minimal example that
addresses all these issues:
class ImageProcessingTask {
var cancelled = false
func process() async -> Image? { … }
}
var currentTask: ImageProcessingTask?
@IBAction func buttonDidClick(sender:AnyObject) {
currentTask?.cancelled = true
let task = ImageProcessingTask()
currentTask = task
beginAsync {
guard let image = await task.process() else { return }
DispatchQueue.main.async {
guard task.cancelled == false else { return }
imageView.image = image
}
}
}
If my example isn't obvious, I've documented my thinking (and some
alternatives) in a gist:
https://gist.github.com/jakob/22c9725caac5125c1273ece93cc2e1e7
Anyway, this more realistic code sample doesn't look nearly as nice any more,
and I actually think this could be implemented nicer without async/await:
class ImageProcessingTask {
var cancelled = false
func process(completionQueue: DispatchQueue, completionHandler: (Image?)->())
{ … }
}
@IBAction func buttonDidClick(sender:AnyObject) {
currentTask?.cancelled = true
let task = ImageProcessingTask()
currentTask = task
task.process(completionQueue: DispatchQueue.main) { (image) in
guard let image = image else { return }
guard task.cancelled == false else { return }
imageView.image = image
}
}
So I wonder: What's the point of async/await if it doesn't result in nicer code
in practice? How can we make async/await more elegant when calling from
non-async functions?
Jakob
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution