"Espere um segundo": por que atrasos em Swift são mágica, não gambiarras
\n\nImagine: você está escrevendo um aplicativo para pedir pizza. O usuário clica em "Pagar" e instantaneamente — bum! — o dinheiro é debitado. Sem animação, sem pausa, sem a sensação de "algo está acontecendo". O usuário se assusta, fecha o aplicativo, e você perde um cliente. Atraso em Swift não é uma muleta, mas uma ferramenta de design de UX e arquitetura adequada.
\n\nA pergunta "How to create a delay in Swift?" no Stack Overflow acumulou dezenas de milhares de visualizações. E não é surpresa: iniciantes tentam usar sleep() (spoiler: não pode), enquanto profissionais buscam soluções elegantes. Vamos analisar 5 maneiras funcionais — desde o clássico GCD até o moderno async/await. Vamos lá!
1. Clássico: DispatchQueue.main.asyncAfter (iOS 4+)
\nA maneira mais popular de criar um atraso em Swift é DispatchQueue.main.asyncAfter. Funciona em qualquer versão do iOS e não requer imports adicionais. É adequado para executar código na thread principal (por exemplo, atualizar a UI).
import UIKit\n\nclass ViewController: UIViewController {\n override func viewDidLoad() {\n super.viewDidLoad()\n \n // Atraso de 2 segundos\n DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {\n print("2 segundos se passaram!")\n self.showAlert()\n }\n }\n \n func showAlert() {\n let alert = UIAlertController(title: "Olá!", message: "Isso é um atraso", preferredStyle: .alert)\n alert.addAction(UIAlertAction(title: "OK", style: .default))\n present(alert, animated: true)\n }\n}\n\nPrós e contras
\n- \n
- Prós: simplicidade, compatibilidade reversa, funciona na thread principal. \n
- Contras: não é possível cancelar o atraso (a menos que você salve o DispatchWorkItem). \n
2. Atraso cancelável via DispatchWorkItem
\nÀs vezes é necessário cancelar um atraso — por exemplo, se o usuário saiu da tela. DispatchWorkItem resolve esse problema. Salvamos uma referência ao "trabalho" e chamamos cancel().
class DelayedTask {\n private var workItem: DispatchWorkItem?\n \n func scheduleDelayedAction() {\n // Criando a tarefa\n let item = DispatchWorkItem { [weak self] in\n print("Tarefa executada após o atraso")\n self?.doSomething()\n }\n \n // Salvando e executando\n workItem = item\n DispatchQueue.main.asyncAfter(deadline: .now() + 3.0, execute: item)\n }\n \n func cancelDelayedAction() {\n workItem?.cancel()\n workItem = nil\n print("Tarefa cancelada")\n }\n \n func doSomething() {\n // Seu código\n }\n}\n\n// Uso\nlet task = DelayedTask()\ntask.scheduleDelayedAction()\n// Cancelando após 1 segundo\nDispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {\n task.cancelDelayedAction()\n}\n\nObserve o [weak self] — isso é obrigatório para evitar vazamentos de memória em Swift. O atraso pode sobreviver ao controlador se a referência não for enfraquecida.
3. Timer.scheduledTimer: atraso com repetição
\nTimers em Swift não são apenas para tarefas repetitivas. Você pode criar um timer de uso único com atraso. Vantagem: o timer é facilmente cancelado e pode ser pausado.
\n\nclass TimerExample {\n var timer: Timer?\n \n func startDelayedAction() {\n // Timer de uso único após 1.5 segundos\n timer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false) { [weak self] _ in\n print("Timer disparou após 1.5 seg")\n self?.updateUI()\n }\n }\n \n func stopTimer() {\n timer?.invalidate()\n timer = nil\n }\n \n func updateUI() {\n // Atualizando a interface\n }\n}\n\nQuando usar Timer
\n- \n