Por que as threads em segundo plano são a dor de cabeça de todo desenvolvedor iOS?
\n\nImagine: você está escrevendo um aplicativo para baixar fotos da internet. Tudo funciona perfeitamente... até o usuário pressionar o botão "Baixar". A tela congela, o aplicativo "trava" e, após alguns segundos, o iOS simplesmente encerra seu processo. Familiar?
\n\nO problema é que todas as operações, por padrão, são executadas na thread principal (main thread). E a thread principal é responsável pela renderização da UI — se você bloqueá-la com uma tarefa longa, a interface deixará de responder aos toques. A solução? Usar uma background thread (thread em segundo plano) em Swift.
\n\nNeste artigo, vamos entender como trabalhar com threads em segundo plano com exemplos reais. Você aprenderá sobre GCD, OperationQueue e o novo async/await do Swift 5.5+. Vamos lá!
\n\nO que é uma thread em Swift?
\n\nUma thread é um processo leve que executa o código do programa. Um aplicativo iOS tem uma thread principal (main thread) e várias threads em segundo plano. A thread principal cuida da UI: atualiza a tela, processa gestos, animações. Tudo que envolve a interface deve acontecer apenas na thread principal.
\n\nAs threads em segundo plano (background threads) são necessárias para:
\n- \n
- Baixar dados da rede \n
- Trabalhar com arquivos (leitura/escrita) \n
- Cálculos complexos (processamento de imagens, criptografia) \n
- Trabalhar com bancos de dados \n
Se você tentar atualizar a UI a partir de uma thread em segundo plano — o aplicativo falhará com um erro, ou você verá um comportamento estranho na interface.
\n\nGCD (Grand Central Dispatch) — a forma clássica
\n\nGrand Central Dispatch (GCD) é uma biblioteca de baixo nível para gerenciamento de threads, embutida no iOS/macOS. Ela funciona através de filas (queues): você coloca uma tarefa em uma fila, e o sistema decide em qual thread executá-la.
\n\nDispatchQueue.main — thread principal
\nSe você precisar executar código na thread principal (por exemplo, atualizar um UILabel), use:
\n\nDispatchQueue.main.async {\n self.label.text = "Download concluído!"\n}\n\nDispatchQueue.global() — thread em segundo plano
\nPara tarefas em segundo plano, use a fila global:
\n\nDispatchQueue.global(qos: .background).async {\n // Trabalho pesado\n let imageData = try? Data(contentsOf: url)\n \n // Retornamos à thread principal para a UI\n DispatchQueue.main.async {\n self.imageView.image = UIImage(data: imageData!)\n }\n}\n\nO parâmetro qos (Quality of Service) define a prioridade da tarefa:
- \n
.userInteractive— o mais alto, para UI \n .userInitiated— o usuário aguarda o resultado \n .utility— tarefas longas (download de arquivos) \n .background— baixa prioridade (sincronização, backups) \n
OperationQueue — mais controle
\n\nOperationQueue é uma camada sobre o GCD com recursos adicionais:
\n- \n
- Cancelamento de tarefas \n
- Dependências entre tarefas \n
- Número máximo de threads paralelas \n
Exemplo de download de várias imagens:
\n\nlet queue = OperationQueue()\nqueue.maxConcurrentOperationCount = 2 // No máximo 2 tarefas simultâneas\n\nlet operation1 = BlockOperation {\n // Download da primeira imagem\n sleep(2)\n print("Foto 1 baixada")\n}\n\nlet operation2 = BlockOperation {\n // Download da segunda imagem\n sleep(3)\n print("Foto 2 baixada")\n}\n\n// operation2 só começará após a conclusão da operation1\noperation2.addDependency(operation1)\n\nqueue.addOperations([operation1, operation2], waitUntilFinished: false)\n\nIsso é útil quando você precisa executar tarefas em ordem estrita ou com limitação de recursos.
\n\nAsync/await moderno (Swift 5.5+)
\n\nA partir do Swift 5.5, Ap