How to Convert Existing Async Code to Use async-await using Swift and iOS

How to Convert Existing Async Code to Use async-await using Swift and iOS

Software engineers are expected to spend a lot of time on improving and modernizing the codebase. If the codebase hasn't been given enough attention, it's possible that the codebase might get deprecated soon and will have undesirable consequences for production users.

In today's blog post, we will see how to convert the legacy async code to use the async await mechanism in Swift on the iOS platform.

  • Existing async code

Imagine we have an existing code that does async processing like this.


private func asyncProcessing(completion: (Bool) -> Void) {
    completion(true)
}

// Can be called with
asyncProcessing { success in

}

However, as time went by, we decided that this is not going to work for long, so we decided to convert it using the async-await mechanism.

  • Converting to use the async-await mechanism

To convert async operation into the modern framework, we will use withCheckedThrowingContinuation API. This is a simple closure that gives us CheckedContinuation object. Once our async operation is completed, we can either return a successful value or a failure based on whether the operation was successful or not.


private func asyncProcessing() async throws -> Bool {
    let isError = Bool.random()
    return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Bool, Error>) in
        if isError {
            continuation.resume(with: .failure(CustomError.genericError))
        } else {
            continuation.resume(returning: true)
        }
    }
}

Please note that in above code, we are simulating either error or success condition by using Bool.random() API. If it's the success, we return true to the CheckedContinuation object. If it fails, we resumt the operaiton with failure enum case associated custom error

Now with API ready, let's call it inside the Task closure,


Task {
    do {
        let asyncProcessingResult: Bool = try await asyncProcessing()
        print("Result is \(asyncProcessingResult)")
    } catch let error as CustomError {
        print(error.localizedDescription)
    } catch {
        print("Generic Error")
    }
}

Summary

And that's it. We successfully converted the legacy async code to use the async-await mechanism and modernized our codebase.

However, we don't need to stop here. It is still possible to create a generic function that will convert any sort of legacy async function into the one using the async-await mechanism. However, in the interest of time and being out of scope, we will leave that for some other day.

Support and Feedback

If you have any comments or questions, please feel free to reach out to me on LinkedIn.

If you like my blog content and wish to keep me going, please consider donating on Buy Me a Coffee or Patreon. Help, in any form or amount, is highly appreciated and it's a big motivation to keep me writing more articles like this.