Translating closures to async
Tags: asyncswift
Published: 2024-04-11 08:27:10

---
title: Translating closures to async
published: true
date: 2024-03-02 08:50:27 UTC
tags: AsyncSwift
canonical_url: https://wesleydegroot.nl/blog/post/Closures-to-Async
---

In this post, we will discuss how to translate closures to async in Swift.

## What is `continuation`?

In Swift, a continuation is a construct that allows you to suspend and resume execution of a piece of code at a later time. It's often used in the context of asynchronous programming.

When you're dealing with asynchronous tasks, you often need to wait for some operation to complete before you can continue with the rest of your code. This is where continuation comes in.

You can think of a continuation as a placeholder for the future result of an asynchronous operation. When the operation is complete, you can "resume" the continuation with the result, allowing the rest of your code to proceed.

In Swift 5.5 and later, continuation is often used in the implementation of async/await patterns. For example, you might use a continuation to wrap a callback-based asynchronous API into a function that can be used with await.

## Use Case: continuation

Imagine you have a function that takes a callback as an argument, and you want to convert it to an async function. Here's an example of what that might look like:

```swift
func fetchData(completion: @escaping (Result<Data, Error>) -> Void) {
    // Perform some asynchronous operation
    // ...
    // When the operation is complete, call the completion handler
    completion(.success(data))
}
```

This function takes a completion handler as an argument, and when the asynchronous operation is complete, it calls the completion handler with the result.

To convert this function to an async function, you can use a continuation. Here's how you might do that:

```swift
func fetchData() async throws -> Data {
    return try await withCheckedThrowingContinuation { continuation in
        fetchData { result in
            switch result {
            case .success(let data):
                continuation.resume(returning: data)
            case .failure(let error):
                continuation.resume(throwing: error)
            }
        }
    }
}
```

Example 2:

Imagine we have a function whihout `Result` type, and we want to convert it to an async function. Here's an example of what that might look like:

```swift
func fetchData(completion: @escaping (Data?, Error?) -> Void) {
    // Perform some asynchronous operation
    // ...
    // When the operation is complete, call the completion handler
    completion(data, error)
}
```

To convert this function to an async function, you can use a continuation. Here's how you might do that:

```swift
func fetchData() async throws -> Data {
    return try await withCheckedThrowingContinuation { continuation in
        fetchData { data, error in
            if let data = data {
                continuation.resume(returning: data)
            } else if let error = error {
                continuation.resume(throwing: error)
            }
        }
    }
}
```

## `withCheckedThrowingContinuation` vs `withUnsafeContinuation`

`withCheckedContinuation` will add runtime checks to detect any improper use of the continuation and warn you if it were to happen. `withUnsafeContinuation` will perform none of these checks.

## Caveats

`continuation` must be called exactly once.

## Wrap up

Continuations are a powerful tool for working with asynchronous code in Swift. They allow you to suspend and resume execution of a piece of code at a later time, making it easier to work with asynchronous operations.

Resources: [https://developer.apple.com/documentation/swift/checkedcontinuation](https://developer.apple.com/documentation/swift/checkedcontinuation)  
[https://developer.apple.com/documentation/swift/withcheckedcontinuation(function:\_:)](https://developer.apple.com/documentation/swift/withcheckedcontinuation(function:_:))