Swift Concurrency Just Got Approachable
2 min read
- #swift
- #concurrency
WWDC25 delivered something I didn’t expect: Swift Concurrency that finally feels natural. After years of verbose annotations and mental juggling between actors and async/await, Apple made it click by aligning it with how iOS developers actually think.
The Big Change
You can now set -default-isolation MainActor in your build settings. That’s it. All declarations in your module are automatically isolated to the main actor, unless explicitly marked otherwise.
// In Xcode build settings:
SWIFT_DEFAULT_ACTOR_ISOLATION = main
// Or in Package.swift:
.swiftSettings([.unsafeFlags(["-Xfrontend", "-default-actor-isolation=main"])])
Think of it like this: instead of having to prove your code is safe for concurrency, you start safe and add concurrency only when you need it.
// Before: annotations everywhere
@MainActor class UserManager {
@MainActor private var user: User?
@MainActor func login() { }
}
// After: clean and simple (enabled by default isolation)
class UserManager {
private var user: User?
func login() { }
}
Why This Matters
Most iOS apps spend 95% of their time on the main thread anyway. We fetch some data, update the UI, and respond to taps. The old concurrency model made us overthink this simple reality.
Now you can build your app like you always have - clean domain objects, straightforward business logic, and add async/await only for the few things that actually need it.
The Domain Win
This changes everything for architecture. You can model your domain clearly and defer concurrency to the parts that need it, without cluttering your logic.
// Start with clear domain modeling
class OrderService {
private var orders: [Order] = []
func createOrder(items: [Item]) -> Order {
let order = Order(items: items)
orders.append(order)
return order
}
// Add async only where it adds value
func syncWithServer() async {
let serverOrders = try await api.fetchOrders()
orders = serverOrders
}
}
Your domain logic stays focused on business rules. Concurrency becomes an implementation detail you add strategically.
The Testing Story
Tests become simpler too. No more wrestling with actor boundaries in your unit tests. Your business logic tests can focus on edge cases and domain rules instead of concurrency concerns, making test setup and mocking much easier.
What This Really Means
Swift Concurrency is finally aligning with how real-world iOS developers build apps, instead of forcing us into academic models. You can work backwards from your domain model, iterate quickly, and optimize for performance only when you need to.
For complex iOS apps, this feels like Swift growing up - supporting real-world development patterns instead of fighting them.
Sometimes the best improvements are the ones that get out of your way.