Back home

SwiftUI Series 10|Chargement asynchrone SwiftUI : liaison entre les tâches, les asynchrones/attentes et l'état de l'interface

Ce qui est vraiment difficile, c'est de maintenir la cohérence du chargement, des résultats, des erreurs et du cycle de vie des pages.

Une fois que de nombreuses pages SwiftUI sont chargées de manière asynchrone, les problèmes commencent à augmenter :

  • onAppear répétera la demande
  • L’état de chargement est instable
  • Les anciens résultats modifieront la page actuelle
  • La tâche est toujours en cours de réécriture après avoir quitté la page

Ces problèmes peuvent ressembler à des problèmes Task ou async/await en surface, mais les raisons les plus fondamentales sont souvent :

Le cycle de vie des tâches asynchrones et le cycle de vie de l’état de la page ne sont pas alignés.

Ce à quoi nous devons vraiment faire face, c’est :

  • Quand commence la demande ?
  • Pourrai-je changer de page après le retour des résultats ?
  • Quand les anciennes tâches doivent-elles expirer ?
  • Comment ces états de chargement/erreur/contenu s’excluent-ils mutuellement ?

1. Le piège le plus simple est de considérer la page asynchrone comme “une requête + une valeur booléenne”

De nombreuses pages seront initialement rédigées ainsi :

-Un isLoading -Un items -Un errorMessage

Ajoutez-en un autre :

Task {
  await load()
}

Bien sûr, cela fonctionnera au début, mais dès que la page commencera à prendre en charge :

  • réessaye
  • Déroulez vers le bas pour actualiser
  • Recherche
  • Commutation conditionnelle

Les problèmes surgiront les uns après les autres. Parce que la vraie page est un ensemble de tâches qui peuvent se remplacer et se recouvrir.

2. Le véritable noyau des pages asynchrones réside dans le flux d’état

Si vous comprenez le chargement asynchrone uniquement comme « récupérer des données », il sera facile d’ignorer que ce qui intéresse vraiment la page, ce sont ces états :

  • Chargement lors de la première entrée
  • Actualiser en fonction du contenu existant
  • Réessayez après un échec de chargement
  • Demande après changement de certaines conditions

Ce sont deux “chargements”, mais ce n’est pas la même chose dans la sémantique des pages. Si tout est représenté par un seul isLoading, la page deviendra vite désordonnée.

Une idée plus pratique est donc généralement :

  • Définissez d’abord dans quel état sémantique se trouve actuellement la page
  • Laissez la tâche asynchrone piloter ce changement de flux d’état

3. onAppear + Task devient souvent plus dangereux à mesure que vous l’écrivez.

Parce que c’est si simple.

Une situation courante est d’écrire naturellement :

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

Ce code en lui-même n’est pas nécessairement faux, mais le danger est qu’il est trop facile d’utiliser par défaut :

  • La page apparaît une fois
  • Demande à envoyer une fois
  • Changer le statut une fois après le retour

Dans des projets réels, ces trois hypothèses peuvent ne pas être vraies.

Par conséquent, la clé pour savoir si le chargement asynchrone est vraiment stable n’est pas de savoir s’il existe Task, mais plutôt :

  • Si des tâches similaires sont gérées de manière uniforme -Si les anciennes tâches seront annulées ou expirées
  • Si le résultat doit être vérifié par rapport au contexte actuel

4. Un malentendu courant : si le résultat est réussi, vous atterrirez directement sur la page.

De nombreuses pages sont dans un état désordonné et la cause profonde est ici.

Par exemple :

  • Les mots clés ont changé
  • Les anciennes demandes reviennent plus tard
  • Les anciens résultats changent toujours la page

Du point de vue de la demande, cela n’a pas échoué, mais du point de vue de la page, il a expiré.

Une chose très importante dans les pages asynchrones est donc :

Tous les résultats renvoyés avec succès ne sont pas automatiquement éligibles pour réécrire l’interface utilisateur actuelle.

Par conséquent, le chargement asynchrone des pages ne peut généralement pas seulement examiner « si le résultat est obtenu », mais doit également examiner « si le résultat est toujours valable maintenant ».

5. Une direction plus stable : fermez la tâche de chargement au lieu de laisser chaque événement de l’interface utilisateur envoyer sa propre requête

Si une page prend en charge :

  • chargement initial
  • réessaye
  • rafraîchir
  • Filtrer les modifications

L’approche la plus stable consiste généralement à regrouper des tâches similaires.

Par exemple :

  • Toutes les entrées appellent finalement le même reload()
  • La tâche actuellement active est détenue par ViewModel
  • Lorsque de nouvelles tâches apparaissent, les anciennes tâches sont annulées ou jugées invalides.

De cette façon, l’état de la page sera au moins plus facile à maintenir cohérent car :

  • Il est clair qui charge
  • Il est également clair qui peut terminer le chargement

6. Conclusion : ce que le chargement asynchrone de SwiftUI doit vraiment gérer, c’est de savoir si l’état de la tâche et de la page peut être clairement expliqué.

Pour le dire sous une forme plus courte, je dirais :

Lorsqu’il s’agit de chargement asynchrone dans SwiftUI, la vraie difficulté est de maintenir la cohérence du cycle de vie des tâches, de la validité des résultats et du flux d’état des pages.

Tant que ces trois choses ne seront pas établies, la page continuera à s’agrandir :

  • Répéter la demande
  • Réécrire les anciens résultats
  • confusion de chargement

Ces problèmes ne peuvent généralement pas être résolus en écrivant quelques Task supplémentaires.

FAQ

What to read next

Related

Continue reading