How to use async/await in synchronous Swift code with tasks
Learn how to use tasks to call async/await methods from synchronous code.
25 Aug 2025 · 3 min read
When working with async/await in Swift, we might need to call async/await methods or properties from synchronous contexts. Since those contexts don't allow the await keyword directly, we need a way to bridge the gap. That's where tasks come in.
Let's jump in and look at an example.

Let's say we have an async function that fetches some data:
func fetchData() async -> String {...}
Now, we want to call it when the user taps on a button inside a SwiftUI view.
struct ContentView: View {var body: some View {Button("Load Data") {await fetchData()}}}
With this in place, we get the compiler error async call in a function that does not support concurrency. A button's action is synchronous, so await doesn't work directly. To solve it, we can wrap the call inside a Task:
struct ContentView: View {var body: some View {Button("Load Data") {Task {await fetchData()}}}}
A Task starts running immediately after creation, and it lets us use await inside otherwise synchronous code. We don't need to hold on to it unless we want extra control (like cancellation).
This pattern is useful in many places where async code meets synchronous APIs. For example, in app lifecycle methods such as application(\_:didFinishLaunchingWithOptions:) in AppDelegate, we can use the same Task { ... } approach to call async methods like requesting push notification permissions.
Tasks give us a clean and lightweight way to bridge between Swift's structured concurrency and existing synchronous code.



Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips



