Back home

SwiftUI Series 10 | Carregamento assíncrono SwiftUI: ligação de tarefa, assíncrono/aguarde e status da interface

O que é realmente difícil é manter o carregamento, os resultados, os erros e o ciclo de vida da página consistentes

Depois que muitas páginas SwiftUI são carregadas de forma assíncrona, os problemas começam a aumentar:

  • onAppear repetirá a solicitação
  • O estado de carregamento é instável
  • Resultados antigos mudarão a página atual de volta
  • A tarefa ainda está sendo escrita de volta depois de sair da página

Esses problemas podem parecer problemas Task ou async/await superficialmente, mas os motivos mais fundamentais são frequentemente:

O ciclo de vida da tarefa assíncrona e o ciclo de vida do estado da página não estão alinhados.

Então, o que realmente temos que lidar é:

  • Quando começa a solicitação?
  • Serei elegível para mudar a página depois que os resultados voltarem?
  • Quando as tarefas antigas devem expirar?
  • Como esses estados de carregamento/erro/conteúdo são mutuamente exclusivos?

1. A armadilha mais fácil é considerar a página assíncrona como “uma solicitação + um valor booleano”

Muitas páginas serão inicialmente escritas assim:

-Um isLoading -Um items -Um errorMessage

Adicione outro:

Task {
  await load()
}

Claro que no começo vai funcionar, mas assim que a página começar a suportar:

  • tente novamente
  • Puxe para baixo para atualizar
  • Pesquisa
  • Comutação condicional

Os problemas surgirão um após o outro. Porque a página real é um conjunto de tarefas que podem se substituir e se cobrir.

2. O verdadeiro núcleo das páginas assíncronas está no fluxo de estado

Se você entender o carregamento assíncrono apenas como “recuperação de dados”, será fácil ignorar que o que realmente interessa à página são estes estados:

  • Carregando ao entrar pela primeira vez
  • Atualizar com base no conteúdo existente
  • Tente novamente após falha no carregamento
  • Solicitação após alteração de certas condições

Ambas são “cargas”, mas não são a mesma coisa na semântica da página. Se tudo for representado por apenas um isLoading, a página logo ficará confusa.

Então uma ideia mais prática geralmente é:

  • Primeiro defina em que estado semântico a página se encontra atualmente
  • Deixe a tarefa assíncrona conduzir essa mudança de fluxo de estado

3. onAppear + Task geralmente se torna mais perigoso quanto mais você o escreve.

Porque é tão fácil.

Uma situação comum é escrever naturalmente:

.onAppear {
  Task {
    await viewModel.load()
  }
}

Este código em si não está necessariamente errado, mas o perigo é que é muito fácil padronizá-lo:

  • A página aparece uma vez
  • Solicitação para enviar uma vez
  • Altere o status uma vez após retornar

Em projetos reais, estas três suposições podem não ser verdadeiras.

Portanto, a chave para saber se o carregamento assíncrono é realmente estável não é se existe Task, mas sim:

  • Se tarefas semelhantes são gerenciadas de maneira uniforme -Se tarefas antigas serão canceladas ou expiradas
  • Se o resultado precisa ser verificado em relação ao contexto atual

4. Um mal-entendido comum: se o resultado for bem-sucedido, você chegará diretamente à página.

Muitas páginas estão em estado desordenado e a causa raiz está aqui.

Por exemplo:

  • Palavras-chave mudaram
  • Pedidos antigos voltam mais tarde
  • Resultados antigos ainda alteram a página

Do ponto de vista da solicitação, ele não falhou, mas do ponto de vista da página, expirou.

Portanto, uma coisa muito importante nas páginas assíncronas é:

Nem todos os resultados retornados com sucesso são automaticamente elegíveis para write-back da UI atual.

Portanto, o carregamento assíncrono de páginas geralmente não pode apenas verificar “se o resultado foi obtido”, mas também “se o resultado ainda é válido agora”.

5. Uma direção mais estável: feche a tarefa de carregamento em vez de permitir que cada evento da UI envie sua própria solicitação

Se uma página suportar:

  • carga inicial
  • tente novamente
  • atualizar
  • Filtrar alterações

A abordagem mais estável geralmente é agrupar tarefas semelhantes.

Por exemplo:

  • Todas as entradas chamam o mesmo reload()
  • A tarefa atualmente ativa é mantida pelo ViewModel
  • Quando novas tarefas aparecem, as tarefas antigas são canceladas ou consideradas inválidas.

Dessa forma, o estado da página será pelo menos mais fácil de manter consistente porque:

  • Está claro quem está carregando
  • Também está claro quem pode encerrar o carregamento

6. Conclusão: O que o carregamento assíncrono do SwiftUI realmente precisa resolver é se a tarefa e o status da página podem ser explicados claramente.

Para resumir, eu diria:

Ao lidar com carregamento assíncrono no SwiftUI, a verdadeira dificuldade é manter consistentes o ciclo de vida da tarefa, a validade dos resultados e o fluxo do estado da página.

Enquanto essas três coisas não forem estabelecidas, a página continuará a crescer:

  • Repetir solicitação
  • Escreva resultados antigos
  • confusão de carregamento

Geralmente, esses problemas não podem ser resolvidos escrevendo mais alguns Task.

FAQ

What to read next

Related

Continue reading