Logo for tanaschita.com

How to use async/await in synchronous Swift code with tasks

Learn how to use tasks to call async/await methods from synchronous code.

14 Mar 2022 · 2 min read

The async/await feature introduced in Swift 5.5 allows us to write asynchronous code in a shorter and safer way. For a recap on async/await, check out this quick guide on async/await in Swift.

In some situations, we need to call async/await methods or properties from synchronous context. How can we do that? Let's look at an example.

The following method uses the UNUserNotificationCenter's async/await methods to ask for authorization to send notifications, then fetches the settings and returns them.

func requestNotificationAuthorization() async throws -> UNNotificationSettings {
let notificationCenter = UNUserNotificationCenter.current()
try await notificationCenter.requestAuthorization(options: [.alert, .sound])
let settings = await notificationCenter.notificationSettings()
return settings
}
Sponsorship logo
Join the FREE iOS Architect Crash Course (for a limited time!)
If you’re a mid/senior iOS developer who’s looking to improve both your skills and salary level, then join this 100% free online crash course. Hurry up because it's available only until November 27th!
Click to get it now

We would like to call this method from our AppDelegate's method applicationDidFinishLaunching(_ application: UIApplication).

Let's try:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
let settings = try await requestNotificationAuthorization()
return true
}

We get the compiler error async call in a function that does not support concurrency. Since the delegate method applicationDidFinishLaunching is not marked with async, we cannot just await a method.

Xcode suggests to add async to the function to resolve the error, but since it's not our function, we cannot just change it.

That's where tasks come in. A task is represented by the Task struct in Swift. When using a Task, we provide a closure that can contain synchronous or asynchronous code to perform.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
Task {
do {
let settings = try await requestNotificationAuthorization()
// Handle settings
} catch {
// Handle error
}
}
return true
}

We don’t need to manually start the task, it starts running immediately after creation. We also don't need to keep a reference to it - only if we need more control over the task like the possibility to cancel.

And that's basically it. Tasks provide us with an easy way to bridge async/await with other Swift code.

Sponsorship logo
Join the FREE iOS Architect Crash Course (for a limited time!)
If you’re a mid/senior iOS developer who’s looking to improve both your skills and salary level, then join this 100% free online crash course. Hurry up because it's available only until November 27th!
Click to get it now

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

async/await

concurrency

swift

Memory management for async/await and tasks in Swift

Learn about weak self references when working with the async/await API.

03 Oct 2022 · 2 min read

Latest articles and tips

© 2022 tanaschita.com

Privacy policy

Impressum