Introdução à concorrência e multithreading em Swift
Os aplicativos modernos para iOS e macOS exigem cada vez mais a execução de várias tarefas simultaneamente. Seja para carregar dados da rede, processar imagens ou realizar cálculos matemáticos complexos — não é possível prescindir de um gerenciamento adequado de threads. Em Swift, a concorrência e o multithreading são implementados no mais alto nível, fornecendo ao desenvolvedor ferramentas poderosas e seguras.
Neste artigo, vamos analisar três abordagens principais: Grand Central Dispatch (GCD), OperationQueue e a moderna palavra-chave async/await, introduzida no Swift 5.5. Você aprenderá como escolher corretamente entre elas e evitar erros típicos, como race condition e deadlock.
Grand Central Dispatch (GCD) — o clássico do multithreading em Swift
Grand Central Dispatch (GCD) é uma biblioteca de baixo nível da Apple que gerencia um pool de threads. O desenvolvedor não precisa criar e destruir threads manualmente — o GCD faz isso automaticamente, distribuindo as tarefas pelos núcleos disponíveis do processador.
Filas principais do GCD
No GCD, existem dois tipos de filas: seriais (serial) e concorrentes (concurrent). As tarefas em uma fila serial são executadas uma após a outra, enquanto em uma fila concorrente podem ser iniciadas simultaneamente.
// Criando uma fila seriallet serialQueue = DispatchQueue(label: "com.example.serial")serialQueue.async { print("Tarefa 1")}serialQueue.async { print("Tarefa 2")}
// Criando uma fila concorrentelet concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)concurrentQueue.async { print("Tarefa concorrente A")}concurrentQueue.async { print("Tarefa concorrente B")}Filas globais e QoS
O GCD fornece filas globais prontas com diferentes prioridades (Quality of Service). Use-as quando não for necessário criar sua própria fila:
.userInteractive— para atualizações de UI (prioridade máxima).userInitiated— para tarefas iniciadas pelo usuário.utility— para operações longas em segundo plano.background— para tarefas não críticas em relação ao tempo
DispatchQueue.global(qos: .userInitiated).async { // Trabalho pesado let result = performComplexCalculation() DispatchQueue.main.async { // Retornamos à thread principal para atualizar a UI self.updateUI(with: result) }}Importante: Sempre atualize a UI apenas na thread principal (DispatchQueue.main). Ignorar esta regra leva a falhas imprevisíveis do aplicativo.
OperationQueue — gerenciamento de dependências de tarefas
Se o GCD é um "canivete suíço", o OperationQueue é um agendador completo com capacidade de cancelamento, priorização e criação de dependências entre operações. Cada operação é uma instância da classe Operation (ou sua subclasse BlockOperation).
Criação e execução de operações
let operationQueue = OperationQueue()operationQueue.maxConcurrentOperationCount = 2 // Limitando o número de operações simultâneas
let operation1 = BlockOperation { print("Operação 1")}let operation2 = BlockOperation { print("Operação 2")}
// Adicionando dependência: operation2 só começará após a conclusão de operation1operation2.addDependency(operation1)
operationQueue.addOperations([operation1, operation2], waitUntilFinished: false)Cancelamento e prioridades
Ao contrário do GCD, o OperationQueue permite cancelar uma operação específica ou toda a fila:
// Cancelando uma operaçãooperation1.cancel()
// Cancelando toda a filaoperationQueue.cancelAllOperations()
// Definindo prioridadeoperation1.