Future
A publisher that eventually produces a single value and then finishes or fails.
Declaration
final class Future<Output, Failure> where Failure : ErrorMentioned in
Overview
Use a future to perform some work and then asynchronously publish a single element. You initialize the future with a closure that takes a Future.Promise; the closure calls the promise with a Result that indicates either success or failure. In the success case, the future’s downstream subscriber receives the element prior to the publishing stream finishing normally. If the result is an error, publishing terminates with that error.
The following example shows a method that uses a future to asynchronously publish a random number after a brief delay:
func generateAsyncRandomNumberFromFuture() -> Future <Int, Never> {
return Future() { promise in
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
let number = Int.random(in: 1...10)
promise(Result.success(number))
}
}
}To receive the published value, you use any Combine subscriber, such as a Subscribers.Sink, like this:
cancellable = generateAsyncRandomNumberFromFuture()
.sink { number in print("Got random number \(number).") }Integrating with Swift Concurrency
To integrate with the async-await syntax in Swift 5.5, Future can provide its value to an awaiting caller. This is particularly useful because unlike other types that conform to Publisher and potentially publish many elements, a Future only publishes one element (or fails). By using the value property, the above call point looks like this:
let number = await generateAsyncRandomNumberFromFuture().value
print("Got random number \(number).")Alternatives to Futures
The async-await syntax in Swift can also replace the use of a future entirely, for the case where you want to perform some operation after an asynchronous task completes.
You do this with the function withCheckedContinuation(isolation:function:_:) and its throwing equivalent, withCheckedThrowingContinuation(isolation:function:_:). The following example performs the same asynchronous random number generation as the Future example above, but as an async method:
func generateAsyncRandomNumberFromContinuation() async -> Int {
return await withCheckedContinuation { continuation in
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
let number = Int.random(in: 1...10)
continuation.resume(returning: number)
}
}
}The call point for this method doesn’t use a closure like the future’s sink subscriber does; it simply awaits and assigns the result:
let asyncRandom = await generateAsyncRandomNumberFromContinuation()For more information on continuations, see the Concurrency topic in the Swift standard library.