Swift Concurrency Series 01|A razão pela qual Swift introduz async/await
É a tentativa do Swift de atualizar a simultaneidade de "dependendo da convenção" para "capacidade de linguagem"
Ao ver async/await pela primeira vez, você o entenderá como uma “versão atualizada da escrita de retorno de chamada”.
Esse entendimento está apenas parcialmente correto.
Se você deseja apenas escrever um código mais curto e um estilo mais síncrono, outras linguagens já fizeram coisas semelhantes. O que o Swift realmente quer resolver é que o antigo modelo assíncrono tornou-se cada vez mais difícil de suportar a complexidade dos projetos iOS modernos.
No passado, talvez você só precisasse processar um clique de botão para enviar uma solicitação, mas agora uma página comum pode envolver:
- Carregue vários recursos em paralelo na primeira tela
- Cancelar tarefas antigas ao sair da página
- Cache local e solicitação remota competem pelo mesmo estado
- Atualizar token automaticamente após o status de login expirar
- As atualizações da UI do thread principal e o processamento em segundo plano ocorrem intercalados
Quando o negócio atinge essa complexidade, o problema assíncrono não é mais apenas um problema de escrita, mas um problema de design de sistema. A importância do async/await é precisamente que ele avança esse tipo de problema de “hábitos no nível da biblioteca” para “regras no nível da linguagem”.
1. O verdadeiro problema do modelo antigo é que o fluxo de controle está quebrado
Todo mundo gosta de usar “callback hell” para explicar os problemas do antigo método de escrita assíncrona, mas se você parar apenas em “o recuo é muito profundo”, ainda não entendeu.
O verdadeiro problema com os retornos de chamada é que o negócio ** é originalmente uma linha, mas o código é dividido em muitos fragmentos discretos. **
Por exemplo, um processo de inicialização muito comum:
- Obtenha informações do usuário atual
- Determine o módulo da página inicial com base nas permissões do usuário
- Extraia os dados da página inicial novamente
- Se falhar, registre os pontos ocultos
- Por fim, retorne ao thread principal para atualizar a IU
Este é um link claramente sequenciado em minha mente. Mas na era da conclusão, esse link costuma ser dividido em:
- um encerramento de solicitação
- Um encerramento de julgamento de permissão
- Várias camadas de tratamento de erros
- Um interruptor de linha principal
- Várias filiais de retorno antecipado
À medida que o código fica mais longo, fica difícil explicar rapidamente:
- Qual é o processo principal?
- Quais galhos serão quebrados
- Quem deve assumir a culpa quando uma etapa falha?
- Você deve continuar depois de sair da página?
A verdadeira dificuldade em manter a lógica assíncrona é que a intenção e a expressão estão fora de sintonia.
2. O maior problema com a conclusão é que ela deixa muitas semânticas-chave para a convenção
conclusão não é uma coisa ruim. Muitas das APIs subjacentes ainda são muito úteis hoje e ainda são adequadas em determinados cenários que exigem vários retornos de chamada, saída de streaming e ponte entre sistemas mais antigos.
O problema é que quando um sistema depende muito da conclusão, muitas das semânticas importantes são apenas “hábitos de equipe” e não regras de linguagem.
Por exemplo, os seguintes itens são frequentemente entendidos por padrão no modelo de conclusão:
- Esse retorno de chamada será chamado uma ou várias vezes?
- O sucesso e o fracasso são estritamente mutuamente exclusivos?
- Em qual thread o retorno de chamada retornará?
- Se o chamador tem a capacidade de cancelar
- Se o objeto for liberado no meio do caminho, os resultados deverão continuar a ser entregues?
Você descobrirá que essas são as questões centrais dos sistemas concorrentes.
Uma vez que essa semântica é mantida por documentação, nomenclatura e experiência, quanto maior o projeto, mais fácil será para a semântica divergir. A coisa mais dolorosa no final geralmente é a incapacidade de raciocinar de maneira estável sobre como um trecho de código assíncrono será executado.
3. Swift introduz async/await, que basicamente reforça as regras do código assíncrono.
O valor de async/await não se trata apenas de:
fetchUser { result in
...
}
Substitua por:
let user = try await fetchUser()
Mais importante ainda, traz de volta ao nível do idioma muitas coisas que estavam originalmente espalhadas na convenção.
Por exemplo agora:
- Uma função
asyncpossui um ponto de retorno claro - A falha é propagada via
throwe não por um estilo diferente de retorno de chamada de resultado awaitinforma explicitamente que este é o ponto de pausa- A cadeia de chamadas assíncronas pode ser lida sem saltar entre vários encerramentos.
O significado desta questão não é “boa aparência”, mas “as regras são mais rígidas”.
O verdadeiro medo dos sistemas complexos são sempre as regras frouxas. Uma vez que as regras são afrouxadas, o código se torna cada vez mais dependente de “essa pessoa simplesmente entende o contexto”.
4. Melhora não apenas a legibilidade, mas também a razoabilidade
Uma situação comum é: consigo entender a conclusão, por que preciso aprender async/await?
A questão não é se você pode entendê-lo hoje, mas:
- Você ainda consegue entender rapidamente depois de três meses?
- Quando os colegas assumem o controle, eles conseguem deduzir o processo com base no próprio código?
- Quando ocorre um bug, é possível caminhar da entrada até a saída?
Esta é a diferença entre “legibilidade” e “razoabilidade”.
Legibilidade é “Este código é agradável aos meus olhos hoje?” A razoabilidade é “Posso julgar com base neste código: como a falha é transmitida, como o cancelamento entra em vigor e em que nível o status é alterado.”
Por exemplo, os seguintes problemas são muitas vezes muito difíceis de resolver no modelo antigo:
- Depois que o usuário sai da página, essa cadeia de solicitações ainda existe?
- Quando a terceira etapa falhar, onde irá parar o status da página final?
- Quando dois resultados assíncronos retornam ao mesmo tempo, quem está qualificado para escrever a IU?
async/await certamente não responderá automaticamente a essas perguntas para a equipe, mas pelo menos permite que essas perguntas sejam colocadas em uma estrutura de processo mais clara, em vez de ocultadas em encerramentos fragmentados.
5. Este assunto está se tornando cada vez mais crítico em projetos iOS
Uma das maiores mudanças no projeto iOS hoje é que “a assincronia passou de uma capacidade marginal para uma capacidade de backbone”.
No passado, assíncrono era mais sobre “clicar e enviar uma solicitação”. Agora participa de forma assíncrona e direta do ciclo de vida da página, máquina de estado, camada de cache, sistema de permissão, sistema de pontos ocultos e até participa do design da velocidade de resposta de todo o produto.
Uma situação comum para uma página comercial real é:
- Haverá uma solicitação de primeira tela assim que a página for aberta.
- Alguns módulos usam cache local para escapar
- Algumas solicitações dependem de perfis de usuário ou configurações experimentais
- Certas operações requerem prevenção de reentrada
- Alguns resultados devem ser retornados ao thread principal para alterar o estado com segurança
Sob esta premissa, se o sistema assíncrono ainda for apenas “cada um escreve sua própria conclusão”, o código logo passará de “pode funcionar” para “ninguém se atreve a mudar”.
Então, o que o async/await realmente percebe é que o assíncrono se tornou o método de trabalho padrão em aplicativos modernos.
6. É a entrada para todo o modelo de simultaneidade do Swift.
Se você observar apenas esse recurso gramatical, async/await parece ser apenas uma expressão assíncrona melhor.
Mas se você olhar para o Swift Concurrency como um todo, na verdade ele está abrindo caminho para recursos subsequentes:
Task: Esclareça os limites das tarefas e o ciclo de vidaMainActor: Restringe a semântica de execução de estados relacionados à IUActor: Isolar estado mutável compartilhado- Simultaneidade estruturada: incorpore subtarefas no ciclo de vida da tarefa pai
Em outras palavras, Swift não está apenas tentando fornecer uma API assíncrona mais conveniente, mas também tentando transformar a “simultaneidade” de uma técnica fragmentada em um conjunto de modelos combináveis, razoáveis e verificáveis por linguagem.
Isso também mostra que async/await não pode ser considerado apenas “mais fácil de escrever”. O que está realmente conectado por trás disso é todo um novo conjunto de filosofias de design de simultaneidade.
7. Não resolve automaticamente todos os problemas, mas muda a natureza do problema.
Também deve ficar claro aqui: com async/await, os bugs de simultaneidade não desaparecerão automaticamente.
Não resolve:
- Desenho errado das fronteiras estaduais
- Tarefas antigas substituem novos resultados
- Um ViewModel assume muitas responsabilidades ao mesmo tempo
- A estratégia de cancelamento da missão não é nada pensada
Mas isso muda uma coisa muito importante: Muitos problemas não são mais “porque a expressão é muito confusa e nem consigo ver como é o problema”, mas “o problema foi claramente expresso”.
Isso pode parecer um retrocesso, mas na verdade é um gigantesco passo à frente. Porque somente quando o problema se torna expressável a depuração, a revisão e a refatoração podem ser eficazes.
8. Conclusão: Swift introduz async/await para não escrever menos fechamentos
Para resumir isso, eu diria:
Swift apresenta
async/awaitpara tornar o código assíncrono compreensível, razoável e sustentável novamente.
Portanto, é o primeiro passo para atualizar o modelo de simultaneidade.
Depois de entender isso, ao olhar para Task, Actor e MainActor posteriormente, você não os considerará como pontos de sintaxe dispersos, mas entenderá que o que o Swift está fazendo é algo maior:
**Reclassifique a simultaneidade de “habilidades empíricas” para “regras de linguagem”. **
What to read next
Want more posts about Swift Concurrency?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #iOS?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home