Boas práticas e padrões · Concorrência · 6 min de leitura
Concorrência em Swift: async/await, Task e actors
Swift traz concorrência estruturada na linguagem: async/await para esperar sem bloquear, Task para lançar trabalho, actors para proteger estado e o compilador checando o que pode cruzar threads.
Arraste para o lado para ver o diagrama inteiro.
async/await e Task
Uma função async pode suspender em cada await sem travar a thread. Para chamá-la a partir de código síncrono, crie uma Task { }; no SwiftUI, prefira o modificador .task { }, que cancela sozinho quando a view some. Para várias chamadas em paralelo, use async let ou withTaskGroup.
Actors e @MainActor
Um actor é como uma classe cujo estado só é acessado por uma tarefa de cada vez: acabam as condições de corrida nesse estado. Quem está fora precisa de await para chamá-lo. @MainActor marca o que deve rodar na thread principal — modelos de tela e atualização de UI.
Cuidado com a reentrância: depois de um await dentro do actor, o estado pode ter mudado. Releia antes de usar.
Sendable e Swift 6
Tipos Sendable podem cruzar fronteiras de concorrência com segurança (structs de valores, actors, classes finais imutáveis). No modo de linguagem Swift 6, o compilador transforma em erro o que antes era só risco de corrida — vale ativar e corrigir aos poucos.
No código: antes e depois
final class ImageCache {
var images: [URL: UIImage] = [:] // acessado de várias threads: corrida
func load(_ url: URL, done: @escaping (UIImage?) -> Void) {
URLSession.shared.dataTask(with: url) { data, _, _ in
let image = data.flatMap(UIImage.init)
self.images[url] = image // escreve fora da main e sem proteção
done(image)
}.resume()
}
} actor ImageCache {
private var images: [URL: UIImage] = [:]
func image(for url: URL) async throws -> UIImage {
if let cached = images[url] { return cached }
let (data, _) = try await URLSession.shared.data(from: url)
guard let image = UIImage(data: data) else { throw URLError(.cannotDecodeContentData) }
images[url] = image // só uma tarefa por vez chega aqui
return image
}
}
@MainActor @Observable final class AvatarModel {
var image: UIImage?
func load(_ url: URL, cache: ImageCache) async {
image = try? await cache.image(for: url) // volta à main por ser @MainActor
}
} O actor protege o dicionário; o modelo @MainActor garante que a UI só é atualizada na thread principal.
Em resumo
- await suspende sem bloquear.
- .task {} no SwiftUI cancela sozinho.
- actor: um acesso ao estado por vez.
- @MainActor para UI; Sendable para cruzar threads.
Perguntar à IA
Monte um prompt pronto sobre Concorrência em Swift: async/await, Task e actors na sua linguagem e no seu caso, e abra num chat gratuito.
O prompt vai para o site que você escolher. Não cole senhas, tokens nem dados reais de clientes. Para Gemini e outros, copie e cole.