Structured concurrency helps you write clear and safe asynchronous code. It keeps tasks organized so they finish properly and errors are handled well.
Structured concurrency in iOS Swift
func example() async { await withTaskGroup(of: Void.self) { group in group.addTask { // async work here } // more tasks can be added } }
withTaskGroup creates a group of tasks that run concurrently.
All tasks inside the group must finish before the group ends.
await withTaskGroup(of: Int.self) { group in group.addTask { 1 } group.addTask { 2 } var sum = 0 for await value in group { sum += value } print(sum) // prints 3 }
await withThrowingTaskGroup(of: String.self) { group in group.addTask { try await fetchData() } for try await result in group { print(result) } }
This SwiftUI app has a button that starts two tasks concurrently. Each task waits some time and then returns a message. The messages show in a list when tasks finish.
import SwiftUI struct ContentView: View { @State private var results = [String]() var body: some View { VStack { Button("Start Tasks") { Task { await runTasks() } } List(results, id: \.self) { item in Text(item) } } .padding() } func runTasks() async { await withTaskGroup(of: String.self) { group in group.addTask { try await Task.sleep(nanoseconds: 1_000_000_000) return "Task 1 done" } group.addTask { try await Task.sleep(nanoseconds: 500_000_000) return "Task 2 done" } for await result in group { await MainActor.run { results.append(result) } } } } }
Structured concurrency helps avoid bugs by making sure all tasks finish or cancel together.
Use withTaskGroup for simple tasks and withThrowingTaskGroup when tasks can throw errors.
Remember to update UI on the main thread if needed, but SwiftUI's @State handles this automatically inside async tasks.
Structured concurrency organizes async tasks into groups that run and finish together.
It makes async code easier to read, write, and maintain.
Use task groups to run multiple tasks concurrently and collect their results safely.