Ответ
Нет, не весь код автоматически выполнится на главном потоке. @MainActor гарантирует, что вход в его неизолированные (nonisolated) свойства и методы будет происходить на главном потоке. Однако, внутри async-метода поток может смениться после точки await.
Проблема и решение:
@MainActor
class MyViewModel {
var data: [String] = []
func fetchAndUpdate() async {
// 1. Эта точка выполняется на главном потоке (гарантия @MainActor).
let newData = await networkService.fetchData() // 2. `await` -> приостановка.
// 3. После возобновления поток МОЖЕТ БЫТЬ ЛЮБЫМ (например, фоновый).
// ОПАСНО: Модификация состояния не на главном потоке.
self.data = newData // Возможна гонка данных и краш UI.
// РЕШЕНИЕ: Явное возвращение на главный актор.
await MainActor.run {
self.data = newData // Теперь безопасно.
}
}
}
Правила и лучшие практики:
- Гарантируется: Синхронный код и код до первого
awaitв методе@MainActor-типа. - Не гарантируется: Код после
await. Исполнитель (Executor) может возобновить выполнение на другом потоке. - Что делать: Все операции, связанные с обновлением состояния (
@Published,@State, UI-методы), которые идут послеawait, нужно оборачивать вawait MainActor.run { ... }.
Вывод: @MainActor обеспечивает изоляцию, но в асинхронном контексте ответственность за выполнение UI-кода на главном потоке после await лежит на разработчике.