CoFuture

public class CoFuture<Value>
extension CoFuture: Hashable
extension CoFuture: CoCancellable

Holder for a result that will be provided later.

CoFuture and its subclass CoPromise are the implementation of the Future/Promise approach. They allow to launch asynchronous tasks and immediately returnCoFuture with its future results. The available result can be observed by the whenComplete() callback or by await() inside a coroutine without blocking a thread.

func makeFutureOne(args) -> CoFuture<Response> {
    let promise = CoPromise<Response>()
    someAsyncFuncWithCallback { response in
        . . . do some work . . .
        promise.success(response)
    }
    return promise
}

func makeFutureTwo(args) -> CoFuture<Response> {
    queue.coroutineFuture {
        let future = makeFutureOne(args)
        . . . do some work . . .
        let response = try future.await()
        . . . create result using response . . .
        return result
    }
 }

func performSomeWork(args) {
    let future = makeFutureTwo(args)
    mainQueue.startCoroutine {
        . . . do some work . . .
        let result = try future.await()
        . . . do some work using result . . .
    }
}

For coroutine error handling you can use standart do-catch statement or use CoFuture as an alternative.

//execute coroutine and return CoFuture<Void> that we will use for error handling
DispatchQueue.main.coroutineFuture {
    let result = try makeSomeFuture().await()
    . . . use result . . .
}.whenFailure { error in
    . . . handle error . . .
}

Apple has introduced a new reactive programming framework Combine that makes writing asynchronous code easier and includes a lot of convenient and common functionality. We can use it with coroutines by making CoFuture a subscriber and await its result.

//create Combine publisher
let publisher = URLSession.shared.dataTaskPublisher(for: url).map(\.data)

//execute coroutine on the main thread
DispatchQueue.main.startCoroutine {
    //subscribe CoFuture to publisher
    let future = publisher.subscribeCoFuture()

    //await data without blocking the thread
    let data: Data = try future.await()
}
  • Initializes a future that invokes a promise closure.

    func someAsyncFunc(callback: @escaping (Result<Int, Error>) -> Void) { ... }
    
    let future = CoFuture(promise: someAsyncFunc)
    

    Declaration

    Swift

    @inlinable
    public convenience init(promise: (@escaping (Result<Value, Error>) -> Void) -> Void)

    Parameters

    promise

    A closure to fulfill this future.

  • Starts a new coroutine and initializes future with its result.

    Note

    If you cancel this CoFuture, it will also cancel the coroutine that was started inside of it.
    func sum(future1: CoFuture<Int>, future2: CoFuture<Int>) -> CoFuture<Int> {
        CoFuture { try future1.await() + future2.await() }
    }
    

    Declaration

    Swift

    @inlinable
    public convenience init(task: @escaping () throws -> Value)

    Parameters

    task

    The closure that will be executed inside the coroutine.

  • Initializes a future with result.

    Declaration

    Swift

    @inlinable
    public convenience init(result: Result<Value, Error>)

    Parameters

    result

    The result provided by this future.

result

  • Returns completed result or nil if this future has not been completed yet.

    Declaration

    Swift

    public var result: Result<Value, Error>? { get }

cancel

  • Returns true when the current future is canceled.

    Declaration

    Swift

    @inlinable
    public var isCanceled: Bool { get }
  • Cancels the current future.

    Declaration

    Swift

    public func cancel()

await

  • Await for the result of this CoFuture without blocking the current thread. Must be called inside a coroutine.

    //execute someSyncFunc() on global queue and return its future result
    let future = DispatchQueue.global().coroutineFuture { someSyncFunc() }
    //start coroutine on main thread
    DispatchQueue.main.startCoroutine {
        //await result of future
        let result = try future.await()
    }
    

    Throws

    The failed result of the CoFuture.

    Declaration

    Swift

    @inlinable
    public func await() throws -> Value

    Return Value

    The value of the CoFuture when it is completed.

  • Await for the result of this CoFuture without blocking the current thread. Must be called inside a coroutine.

    Throws

    The failed result of the CoFuture.

    Declaration

    Swift

    public func await(timeout: DispatchTimeInterval) throws -> Value

    Parameters

    timeout

    The time interval to await for a result.

    Return Value

    The value of the CoFuture when it is completed.

map

  • When future is fulfilled, run the provided callback, which performs a synchronous computation and return transformed value.

    Declaration

    Swift

    @inlinable
    public func map<NewValue>(_ transform: @escaping (Value) throws -> NewValue) -> CoFuture<NewValue>

    Parameters

    transform

    Function that will receive the value and return a new transformed value or throw an error.

    Return Value

    A future that will receive the eventual value.

  • When future is in an error state, run the provided callback, which can recover from the error and return a new value.

    Declaration

    Swift

    @inlinable
    public func recover(_ transform: @escaping (Error) throws -> Value) -> CoFuture

    Parameters

    transform

    Function that will receive the error and return a new value or throw an error.

    Return Value

    A future that will receive the recovered value.

  • When future is fulfilled, run the provided callback, which performs a synchronous computation and return transformed result.

    Declaration

    Swift

    public func mapResult<NewValue>(_ transform: @escaping (Result<Value, Error>) -> Result<NewValue, Error>) -> CoFuture<NewValue>

    Parameters

    transform

    Function that will receive the result and return a new transformed result.

    Return Value

    A future that will receive the eventual result.

flatMap

  • When the current CoFuture is fulfilled, run the provided callback, which will provide a new CoFuture.

    This allows you to dynamically dispatch new asynchronous tasks as phases in a longer series of processing steps. Note that you can use the results of the current CoFuture when determining how to dispatch the next operation.

    Declaration

    Swift

    @inlinable
    public func flatMap<NewValue>(_ callback: @escaping (Value) -> CoFuture<NewValue>) -> CoFuture<NewValue>

    Parameters

    callback

    Function that will receive the value and return a new CoFuture.

    Return Value

    A future that will receive the eventual value.

  • When the current CoFuture is in an error state, run the provided callback, which may recover from the error by returning a CoFuture.

    Declaration

    Swift

    @inlinable
    public func flatMapError(_ callback: @escaping (Error) -> CoFuture) -> CoFuture

    Parameters

    callback

    Function that will receive the error value and return a new value lifted into a new CoFuture.

    Return Value

    A future that will receive the recovered value.

  • When the current CoFuture is fulfilled, run the provided callback, which will provide a new CoFuture.

    Declaration

    Swift

    public func flatMapResult<NewValue>(_ callback: @escaping (Result<Value, Error>) -> CoFuture<NewValue>) -> CoFuture<NewValue>

    Parameters

    callback

    Function that will receive the result and return a new CoFuture.

    Return Value

    A future that will receive the eventual value.

whenComplete

  • Adds an observer callback that is called when the CoFuture has any result.

    Declaration

    Swift

    @inlinable
    public func whenComplete(_ callback: @escaping (Result<Value, Error>) -> Void)

    Parameters

    callback

    The callback that is called when the CoFuture is fulfilled.

  • Adds an observer callback that is called when the CoFuture has a success result.

    Declaration

    Swift

    @inlinable
    public func whenSuccess(_ callback: @escaping (Value) -> Void)

    Parameters

    callback

    The callback that is called with the successful result of the CoFuture.

  • Adds an observer callback that is called when the CoFuture has a failure result.

    Declaration

    Swift

    @inlinable
    public func whenFailure(_ callback: @escaping (Error) -> Void)

    Parameters

    callback

    The callback that is called with the failed result of the CoFuture.

  • Adds an observer callback that is called when the CoFuture is canceled.

    Declaration

    Swift

    @inlinable
    public func whenCanceled(_ callback: @escaping () -> Void)

    Parameters

    callback

    The callback that is called when the CoFuture is canceled.

  • Adds an observer callback that is called when the CoFuture has any result.

    Declaration

    Swift

    @inlinable
    public func whenComplete(_ callback: @escaping () -> Void)

    Parameters

    callback

    The callback that is called when the CoFuture is fulfilled.

hashable

  • Declaration

    Swift

    @inlinable
    public static func == (lhs: CoFuture, rhs: CoFuture) -> Bool
  • Declaration

    Swift

    @inlinable
    public func hash(into hasher: inout Hasher)

publisher

  • Returns a publisher that emits result of this CoFuture.

    Declaration

    Swift

    public func publisher() -> AnyPublisher<Value, Error>