Actor é um tipo introduzido no Swift 5.5+ que resolve o problema de condições de corrida ao nível da linguagem. Ao contrário de bloqueios manuais e filas DispatchQueue, um actor isola automaticamente o seu estado e sincroniza o acesso a ele. Isso significa que duas threads não podem modificar simultaneamente a mesma propriedade de um tipo actor, eliminando condições de corrida sem esforço adicional do desenvolvedor. O mecanismo é baseado no conceito de isolamento de actor, onde o compilador rastreia o acesso às propriedades e métodos do actor. De acordo com a Apple, 2025, o modelo de actor é uma parte fundamental do sistema de concorrência do Swift.
Pontos Principais
Actor é um tipo de referência, semelhante a uma classe, mas com proteção automática contra condições de corrida. Foi introduzido no Swift 5.5 como parte do sistema de concorrência juntamente com async/await e Task. Um actor garante que o seu estado mutável nunca será lido ou escrito simultaneamente a partir de diferentes threads sem sincronização explícita.
Para declarar um actor, usa-se a palavra-chave actor seguida de chaves com os seus membros. Sintaticamente, um actor assemelha-se a uma classe, mas o seu comportamento difere radicalmente.
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
self.balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func getBalance() -> Double {
return balance
}
}
O compilador isola automaticamente todas as propriedades e métodos do actor para que sejam acessíveis apenas dentro do contexto do actor. Ao tentar aceder a balance a partir do exterior do actor, o compilador gerará um erro se a chamada não estiver marcada como async.
O isolamento de dados é o conceito-chave de um actor. Um actor garante acesso mutuamente exclusivo ao seu estado através do mecanismo do executor do actor. Cada actor tem o seu próprio executor que processa sequencialmente todos os acessos aos seus membros isolados.
Quando o código fora de um actor chama o seu método, a chamada é colocada na fila do executor do actor. O actor executa apenas uma tarefa de cada vez, garantindo a ausência de condições de corrida. Se duas threads chamarem deposit simultaneamente, a segunda chamada aguarda a conclusão da primeira.
let account = BankAccount(initialBalance: 1000.0)
// Chamada assíncrona — necessária a partir do exterior do actor
await account.deposit(amount: 500.0)
let currentBalance = await account.getBalance()
Cada chamada a um método do actor requer await porque o actor pode estar ocupado com outra tarefa. Isto não é um erro, mas sim uma conceção deliberada que previne condições de corrida. O Swift torna implicitamente os getters e setters das propriedades do actor async, por isso ler uma propriedade também requer await.
Actor e classe são ambos tipos de referência, mas o seu comportamento num ambiente multithread difere drasticamente. Uma classe não fornece qualquer proteção automática contra condições de corrida, enquanto um actor a incorpora ao nível do compilador através do sistema de tipos.
| Característica | Actor | Classe |
|---|---|---|
| Proteção contra corridas | Automática, ao nível do compilador | Requer sincronização manual |
| Acesso a propriedades | Apenas via await do exterior | Direto, sem sincronização |
| Herança | Apenas de outros actors | Herança de classes padrão |
| Conformidade com protocolos | Pode estar em conformidade com protocolos | Padrão |
| Desempenho | Baixa sobrecarga com isolamento | Mais rápido sem sincronização |
Um actor só pode herdar de outro actor e não pode herdar de uma classe. Isto é intencional porque uma classe carece do mecanismo de isolamento de actor, e misturar tipos quebraria as garantias de segurança.
actor SavingsAccount: BankAccount {
func applyInterest(rate: Double) {
let interest = balance * rate
balance += interest
}
}
As chamadas assíncronas são o mecanismo para interagir com um actor a partir de código externo. Uma vez que um actor isola o seu estado, qualquer acesso aos seus membros a partir do exterior requer await. Isto permite que o Swift garanta que o código chamador não bloqueia a thread e que o actor possa processar outros pedidos.
Além dos tipos de actor declarados, o Swift suporta atores globais — o atributo @MainActor, que marca classes, propriedades ou métodos como executáveis na thread principal. Isto é especialmente útil para código de UI em aplicações iOS.
@MainActor
class ViewModel: ObservableObject {
@Published var title: String = ""
func updateTitle() {
// Este código está garantido para ser executado na thread principal
title = "New Title"
}
}
Usar @MainActor elimina a necessidade de chamar manualmente DispatchQueue.main.async, tornando o código mais limpo e seguro. O compilador verifica que a mudança para a thread principal ocorre corretamente.
Nonisolated é uma palavra-chave que permite marcar um método ou propriedade calculada de um actor como não isolado. Esses membros não têm acesso ao estado isolado do actor, mas podem ser chamados sem await a partir do exterior do actor.
Os métodos nonisolated são úteis para cálculos que não dependem do estado mutável do actor. Por exemplo, o método formatBalance não acede a balance diretamente, apenas formata o valor passado — tal método é seguro para ser tornado nonisolated.
actor BankAccount {
private var balance: Double = 0
nonisolated func formatBalance(amount: Double) -> String {
return "$\(amount)"
}
}
Os membros nonisolated executam-se sincronamente e não requerem await. No entanto, não podem ler propriedades isoladas do actor diretamente. Se um método nonisolated precisar de um valor do actor, deve ser passado como parâmetro.
Reentrancy é um mecanismo que permite a reentrada num actor durante a espera de uma chamada assíncrona. Sem reentrancy, um actor poderia ficar bloqueado para sempre se um dos seus métodos esperasse por outro que, por sua vez, esperasse pelo primeiro.
Quando o código dentro de um actor executa await, o actor suspende a tarefa atual e pode processar outra tarefa na fila. Após a conclusão do await, a tarefa é retomada. Isto evita impasses, mas requer cuidado: o estado do actor entre pontos de await pode mudar.
actor DataProcessor {
var cache: [Int: String] = [:]
func process(id: Int) async -> String {
if let cached = cache[id] {
return cached
}
// await — ponto de reentrada
let result = await fetchData(id: id)
// A cache pode ter mudado após await — reverificar
cache[id] = result
return result
}
}
Os desenvolvedores devem ter em conta a reentrada e verificar o estado do actor após os pontos de await. Um erro típico é assumir que o isolamento do actor persiste através de pontos de suspensão assíncronos. Na prática, entre await e a instrução seguinte, o estado pode diferir do esperado.
Perguntas Frequentes
Actor isola automaticamente o seu estado de condições de corrida, exigindo await para acesso externo. Uma classe não fornece essa proteção — o desenvolvedor é responsável pela sincronização através de bloqueios ou filas. Um actor só herda de um actor, uma classe de uma classe.
Sim, um actor pode herdar de outro actor. A subclasse obtém todas as propriedades e métodos isolados do progenitor. Um actor não pode herdar de uma classe porque as classes carecem do mecanismo de isolamento de actor ao nível do compilador.
Um contexto actor-isolated é uma área de código onde o acesso direto ao estado mutável do actor é permitido. Dentro dos métodos do actor marcados como isolados (por defeito), podem ler-se e escrever-se propriedades sem await. O compilador verifica os limites do isolamento.
Os dados de um actor são passados através de métodos async que retornam tipos Sendable, ou através de métodos nonisolated que aceitam valores como parâmetros. Pode também criar-se uma propriedade async que retorna um instantâneo do estado do actor como uma estrutura Sendable.
Sim, um actor pode estar em conformidade com protocolos. Se um protocolo contiver requisitos isolados (actor-isolated), estes tornam-se automaticamente isolados do actor. Para métodos assíncronos em protocolos, pode especificar-se que devem ser chamados num actor específico usando o marcador isolated.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também