How to bridge async/await functions to Combine's Future type in Swift
Learn how to call async/await code within Combine based APIs.
22 Aug 2022 · 2 min read
When working with asynchronious code in Swift, we might have to find ways to mix and connect different asynchronious patterns like using the Combine framework together with Swift's async/await API.
In this article, we'll look at how to call async-marked functions within Combine based APIs.

Let's look at the following async function which loads a user from server with the async/await pattern.
func loadUser() async throws -> User {// Load user from serverreturn user // or throw error}
To implement the same behaviour with Combine, its Future publisher comes in handy. A future is initialized with a closure that takes a Future.Promise. After doing some asynchronous work, we call that closure with a Result that is either a success or a failure. Combine then automatically maps the result into proper publisher events.
Let's look at how the async function above could be implemented with a Future publisher:
func loadUser() -> Future<User, Error> {return Future() { promise in// Load user from server.promise(.success(user)) // or promise(.failure(error))}}
But since we already have an implementation that loads a user, we'd like to avoid duplication writing the same logic twice.
So let's try to find a more generic solution, that allows us to convert an async func to a Future publisher.
extension Future where Failure == Error {convenience init(asyncFunc: @escaping () async throws -> Output) {self.init { promise inTask {do {let result = try await asyncFunc()promise(.success(result))} catch {promise(.failure(error))}}}}}
In the code above, we extend the Future type with a convenience initializer that allows us to initialize an instance with an async closure. Applied to our example:
func loadUser() -> Future<Int, Error> {return Future(asyncFunc: {try await loadUser()})}
For non-throwing async functions, we could add another extension:
extension Future where Failure == Never {convenience init(asyncFunc: @escaping () async -> Output) {self.init { promise inTask {let result = await asyncFunc()promise(.success(result))}}}}
With a generic solution like this, we now have the possibility to use it on any async function to bridge it to Combine's Future type.

Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips