Introdução: Por Que Você Precisa de Filas de Tarefas em Swift?
No desenvolvimento moderno para iOS e macOS, o desempenho do aplicativo depende diretamente de quão eficientemente você gerencia as threads. Operações de longa duração — carregar dados da rede, processar imagens, trabalhar com banco de dados — não devem bloquear a thread principal (Main Thread), que é responsável pela interface. Se a thread principal estiver ocupada, o usuário vê uma tela "congelada", e o sistema pode forçar o encerramento do aplicativo.
As Filas de Tarefas resolvem esse problema. Elas permitem executar código de forma assíncrona, em paralelo ou sequencialmente, sem bloquear a UI. Em Swift, existem três ferramentas principais para isso: Grand Central Dispatch (GCD), OperationQueue e o modelo moderno async/await (Swift Concurrency). Neste artigo, vamos detalhá-las com exemplos práticos e descobrir quando usar cada uma.
1. Grand Central Dispatch (GCD): A Abordagem Clássica
GCD é uma biblioteca C de baixo nível que gerencia um pool de threads. Em Swift, é conveniente trabalhar com ela através de filas globais (DispatchQueue).
1.1. Principais Tipos de Filas no GCD
- Main Queue — uma fila serial na thread principal. Usada para atualizar a UI.
- Global Queues — filas concorrentes com diferentes prioridades (QoS:
.userInteractive,.userInitiated,.utility,.background). - Custom Queues — filas que você mesmo cria (podem ser seriais ou concorrentes).
1.2. Exemplo: Carregando Dados em Segundo Plano e Atualizando a UI
Suponha que precisamos carregar JSON de um servidor remoto e exibir o resultado em uma tabela.
DispatchQueue.global(qos: .userInitiated).async { // 1. Trabalho em segundo plano: carregando dados guard let url = URL(string: "https://api.example.com/data") else { return } let data = try? Data(contentsOf: url) // 2. Retornar à thread principal para atualizar a UI DispatchQueue.main.async { // Atualizar o modelo de dados ou a tabela self.tableView.reloadData() }}1.3. Usando DispatchGroup para Sincronização
Quando você precisa executar várias tarefas paralelas e esperar que todas sejam concluídas, use DispatchGroup.
let group = DispatchGroup()var images: [UIImage] = []
for url in imageURLs { group.enter() DispatchQueue.global().async { if let data = try? Data(contentsOf: url), let image = UIImage(data: data) { images.append(image) } group.leave() }}
group.notify(queue: .main) { print("All images loaded: \\(images.count)") // Update UI}2. OperationQueue: Um Nível Mais Alto de Abstração
OperationQueue é construído sobre o GCD, mas fornece capacidades adicionais: cancelar tarefas, dependências entre operações e controlar o número máximo de operações concorrentes.
2.1. Criando e Executando Operações
As operações podem ser criadas usando BlockOperation ou subclassificando Operation.
let queue = OperationQueue()queue.maxConcurrentOperationCount = 2 // Limitar a 2 tarefas paralelas
let operation1 = BlockOperation { print("Operation 1 started") sleep(2) print("Operation 1 finished")}
let operation2 = BlockOperation { print("Operation 2 started") sleep(1) print("Operation 2 finished")}
// Definir dependência: operation2 só iniciará após operation1operation2.addDependency(operation1)
queue.addOperations([operation1, operation2], waitUntilFinished: false)2.2. Cancelando Operações
Diferente do GCD, as operações podem ser canceladas. Isso é crítico se o usuário navegar para fora da tela, enquanto