Como parar de temer atrasos e amar o GCD em Swift 3, 4 e 5
\n\nVocê já escreveu um código que deveria ser executado após três segundos, mas disparou instantaneamente? Ou, ao contrário, esperou uma eternidade, embora planejasse alguns milissegundos? Familiar? Então você certamente já encontrou o dispatch_after — uma das ferramentas mais populares, mas também mais traiçoeiras do Grand Central Dispatch (GCD).
\n\nAntigamente, na era do Swift 2 e Objective-C, esse método parecia um feitiço: dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(nanoseconds)), dispatch_get_main_queue()). Mas com a chegada do Swift 3, 4 e 5, a API do GCD foi completamente reescrita. Agora não é apenas uma mudança de nome — é uma nova forma de pensar. Neste artigo, vamos explorar como escrever dispatch_after em Swift em todas as versões atuais, desmistificar mitos e fornecer soluções prontas. Vamos lá!
O que aconteceu com o dispatch_after? Uma breve história de dor
\nAntes do Swift 3, os desenvolvedores usavam o GCD no estilo C:
\nlet delay = dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC)))\ndispatch_after(delay, dispatch_get_main_queue()) {\n print("Olá do passado!")\n}\nIsso funcionava, mas era complicado. No Swift 3, a Apple decidiu "swiftificar" o GCD, transformando-o em uma API orientada a objetos. Agora, o dispatch_after se tornou o método asyncAfter da estrutura DispatchQueue. E isso não é apenas uma reforma cosmética — é uma sintaxe completamente nova que exige compreensão.
Receita básica: asyncAfter em Swift 3, 4 e 5
\nIndependentemente da versão do Swift (3, 4 ou 5), a sintaxe básica do dispatch_after agora é a mesma. Aqui está o exemplo mais simples de execução atrasada na thread principal:
\n\nlet delayInSeconds: Double = 2.0\nDispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) {\n print("2 segundos se passaram!")\n}\nPontos-chave:
\n- \n
- DispatchQueue.main — thread principal (UI). \n
- .now() + delayInSeconds — criamos um deadline (prazo final) relativo ao momento atual. \n
- asyncAfter — execução assíncrona após o tempo especificado. \n
Este código funciona no Swift 3.0, 4.0 e 5.0 sem alterações. A mágica é que a Apple manteve esta API estável desde 2016.
\n\nE o dispatch_time? Trabalhando com nanossegundos
\nÀs vezes você precisa especificar um atraso em nanossegundos (por exemplo, para temporizadores precisos ou lógica de jogos). Na nova API, usa-se DispatchTime:
\nlet nanoseconds: Int = 1_500_000_000 // 1.5 segundos\nlet deadline = DispatchTime.now() + .nanoseconds(nanoseconds)\nDispatchQueue.global().asyncAfter(deadline: deadline) {\n print("Executado após 1.5 segundos na thread de fundo")\n}\nVocê também pode usar constantes prontas: .seconds(5), .milliseconds(500) e até .microseconds(1000). Isso é mais conveniente do que multiplicar por NSEC_PER_SEC.
Perguntas frequentes (e respostas!) sobre dispatch_after em Swift
\nNo Stack Overflow, esta pergunta acumulou milhares de visualizações. Aqui estão os erros mais comuns que os iniciantes cometem.
\n\n1. Por que meu código é executado imediatamente, e não com atraso?
\nO erro mais comum é a confusão entre asyncAfter e async. Se você esqueceu de especificar deadline: ou escreveu DispatchQueue.main.async { ... }, o código será executado imediatamente. A segunda causa: passar um valor negativo. .now() + (-5.0) é um tempo passado, e o GCD executará o bloco imediatamente.
2. Como cancelar um dispatch_after?
\nAo contrário do Timer, o asyncAfter não possui um método cancel() embutido. Mas existem duas soluções:
- \n
- Flag de cancelamento: Use um
Dispatc