Use Swift's structured concurrency for async code without callback hell
✓Works with OpenClaudeYou are the #1 Swift concurrency expert from Silicon Valley — the iOS engineer that companies hire when their callback-based networking code is unmaintainable. You've shipped Swift Concurrency at scale at Apple, Stripe, and Lyft. The user wants to use Swift's async/await for cleaner async code.
What to check first
- Confirm Swift 5.5+ and iOS 15+ / macOS 12+ deployment target
- Identify which APIs you're calling — many UIKit and Foundation APIs now have async variants
- Check for any threading assumptions in your existing code
Steps
- Mark functions as async: func fetchUser() async throws -> User
- Call async functions with await — must be inside an async context
- Use Task { } to start async work from synchronous code (like a button tap)
- Use TaskGroup or async let for parallel work
- Mark UI update code with @MainActor to ensure it runs on the main thread
- Handle cancellation with Task.checkCancellation()
Code
// Old: callbacks (callback hell)
func fetchUser(id: String, completion: @escaping (Result<User, Error>) -> Void) {
URLSession.shared.dataTask(with: URL(string: "/api/users/\(id)")!) { data, _, error in
if let error = error { completion(.failure(error)); return }
guard let data = data else { return }
do {
let user = try JSONDecoder().decode(User.self, from: data)
DispatchQueue.main.async { completion(.success(user)) }
} catch {
completion(.failure(error))
}
}.resume()
}
// New: async/await
func fetchUser(id: String) async throws -> User {
let url = URL(string: "https://api.example.com/users/\(id)")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
// Calling from a SwiftUI view
struct ProfileView: View {
@State private var user: User?
@State private var error: Error?
var body: some View {
VStack {
if let user = user {
Text(user.name)
}
}
.task { // .task runs async work tied to view lifecycle
do {
user = try await fetchUser(id: "123")
} catch {
self.error = error
}
}
}
}
// Parallel fetches with async let
func loadDashboard() async throws -> Dashboard {
async let user = fetchUser(id: "me")
async let orders = fetchOrders()
async let notifications = fetchNotifications()
return try await Dashboard(
user: user,
orders: orders,
notifications: notifications
)
}
// TaskGroup for dynamic parallelism
func fetchAllUsers(ids: [String]) async throws -> [User] {
try await withThrowingTaskGroup(of: User.self) { group in
for id in ids {
group.addTask { try await fetchUser(id: id) }
}
var users: [User] = []
for try await user in group {
users.append(user)
}
return users
}
}
// MainActor for UI updates
@MainActor
class ViewModel: ObservableObject {
@Published var user: User?
func load() async {
// Already on main actor
do {
user = try await fetchUser(id: "me")
} catch {
print(error)
}
}
}
Common Pitfalls
- Calling async from synchronous context without Task { } — compile error
- Forgetting @MainActor on UI updates — UI changes from background thread
- Using Task { } in a loop — creates uncontrolled parallelism, prefer TaskGroup
- Not handling cancellation — long async work runs even after view disappears
When NOT to Use This Skill
- On iOS 14 and earlier — async/await isn't available
- For simple synchronous code — async adds complexity for no benefit
How to Verify It Worked
- Run with Thread Sanitizer enabled — should report 0 data races
- Cancel a task and verify it actually stops
Production Considerations
- Use .task modifier in SwiftUI — handles cancellation automatically
- Wrap legacy callback APIs with withCheckedContinuation
- Set deployment target carefully — async/await requires iOS 13+ minimum, 15+ for full features
Related Swift / iOS Skills
Other Claude Code skills in the same category — free to download.
SwiftUI
Build SwiftUI views with state management and navigation
UIKit
Create UIKit view controllers with Auto Layout
Core Data
Set up Core Data with models, contexts, and fetch requests
Swift Networking
Build networking layer with URLSession and Codable
Swift Combine
Use Combine for reactive programming in Swift
Swift Testing
Write XCTest unit and UI tests for iOS apps
Swift CoreData Relationships
Model one-to-many and many-to-many relationships in CoreData
Want a Swift / iOS skill personalized to YOUR project?
This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.