I have a legacy API function that will provide a UIViewController. It takes as an argument a completion function. The view controller will call the completion function once after being presented with a result value.
func makeController(completion: @escaping (ViewResult) -> Void) -> UIViewController
I would like to wrap this in a slightly nicer API for async so that it becomes something like this:
func makeController() -> (UIViewController, FutureIsh<ViewResult>)
Where the FutureIsh, would have a caller facing interface similar to Task so that you can await futureish.value.
I'm wondering if there is an existing suitable type FutureIsh? I don't think I can use Task because its work block has to be given to it. I think I can make something with an actor, but if there's an existing type I'd prefer to use it.
Attempting to write this with Task, perhaps I could do…
func makeController() -> (UIViewController, Task<ControllerResult>) {
// This doesn't exist, and I can't see it is possible to create
// it with `withCheckedContinuation`.
let task = Task<ControllerResult, Never>.taskWithAPromise()
// Use the legacy API…
let controller = makeController(completion: task.promise)
return (controller, task)
}
I think you can use an AsyncStream that only produces one elemen.
AsyncStream.Continuation is allowed to escape. You can use makeStream to get an "escaped" continuation and an AsyncStream.
Assuming ViewResult is Sendable, you can do
func makeController(completion: @escaping (ViewResult) -> Void) -> UIViewController {
...
}
func makeController() -> (UIViewController, Task<ViewResult, Never>) {
let (stream, continuation) = AsyncStream.makeStream(of: ViewResult.self)
// Here we wrap the AsyncStream into a Task
// you can also just return the AsyncStream directly and let the caller consume it,
// or Task.detached depending on what you need
let task = Task {
var iterator = stream.makeAsyncIterator()
return await iterator.next()!
}
return (makeController {
continuation.yield($0)
continuation.finish()
}, task)
}
Usage:
let (vc, task) = makeController()
print(vc)
print(await task.value)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With