0
0
iOS Swiftmobile~5 mins

Structured concurrency in iOS Swift

Choose your learning style9 modes available
Introduction

Structured concurrency helps you write clear and safe asynchronous code. It keeps tasks organized so they finish properly and errors are handled well.

When you want to run multiple tasks at the same time and wait for all to finish.
When you need to cancel a group of related tasks together.
When you want to avoid messy code with callbacks or manual thread management.
When you want your app to stay responsive while doing background work.
When you want to handle errors from multiple tasks in one place.
Syntax
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.

Examples
This example runs two tasks that return numbers and sums their results.
iOS Swift
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
}
This example shows how to handle errors in tasks using a throwing task group.
iOS Swift
await withThrowingTaskGroup(of: String.self) { group in
  group.addTask { try await fetchData() }
  for try await result in group {
    print(result)
  }
}
Sample App

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.

iOS Swift
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)
        }
      }
    }
  }
}
OutputSuccess
Important Notes

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.

Summary

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.