Swift 6, can @MainActor do async work?
Yes — @MainActor isolation and doing async work aren’t mutually exclusive at all. A @MainActor-isolated function can be async and can await other async work; the actor isolation just controls where the synchronous parts of your code run (on the main thread/executor), not whether you can suspend.
A few things worth being precise about:
1. Being @MainActor doesn’t block the thread while you await
@MainActor
func loadData() async {
updateUI(state: .loading) // runs on main actor
let data = await fetchFromNetwork() // suspends here, main thread is free
updateUI(state: .loaded(data)) // resumes back on main actor
}
While suspended at the await, the main actor isn’t blocked — other main-actor work can run during that gap. When fetchFromNetwork() completes, execution hops back to the main actor to continue.
2. Calling non-isolated async functions from a @MainActor context
If fetchFromNetwork() isn’t itself @MainActor, it runs off the main actor (wherever the underlying executor schedules it), and control returns to the main actor after the await completes. This is the normal way to keep heavy work off the main thread while still updating UI safely afterward.
3. @MainActor on a whole type
@MainActor
class ViewModel: ObservableObject {
@Published var items: [Item] = []
func refresh() async {
items = await repository.fetchItems() // repository call can hop off-actor internally
}
}
All synchronous methods/properties are main-actor-isolated (safe to touch from other main-actor code without await), but async methods can freely suspend and do work elsewhere.
4. Common Swift 6 gotcha
Under strict concurrency, if you call a @MainActor function from a non-isolated context, you need await, since crossing into the actor requires a potential suspension:
Task { @MainActor in
await someMainActorAsyncFunc()
}
So: @MainActor gives you thread-safety/isolation guarantees for the actor’s mutable state, while async gives you the ability to suspend — they compose fine together, and in fact this combo (@MainActor func foo() async) is extremely common for things like view models kicking off network calls.