AsyncImage avant iOS 15

Avec iOS15 est arrivée une solution élégante pour gérer l’affichage d’images à partir d’une URL. La nouvelle vue AsyncImage remplit ce rôle.

AsyncImage(url: imageURL)

Pour un affichage prenant en compte les délais et éventuelles erreurs, la vue peut s’utiliser sous cette forme :

Swift

Phase est une énumération qui contient .empty tant que l’image n’est pas arrivée, .failure, si la requête échoue, et .success avec l’image en paramètre dès que l’image est disponible.
Ces options permettent d’afficher un indicateur d’attente pendant le chargement, comme par exemple la ProgressView standard, ou une image générique en cas d’erreur (dans l’exemple, un simple Color.red).

Si nous souhaitons garder la compatibilité avec les systèmes plus anciens, nous devons construire notre propre vue, ainsi qu’un objet gérant la requête internet.

Nous souhaitons obtenir le même résultat avec un appel similaire :

Swift

La vue AsyncImage14 prend l’url en paramètre, et accepte aussi une closure dans laquelle on pourra comme pour AsyncImage gérer les différentes situations : attente, affichage, erreur.

Nous allons définir une enum phase comme pour l’original :

Swift

La vue AsyncImage14 va servir de conteneur pour les vues que renverra la closure. Nous allons utiliser un type générique pour accepter ces vues.

Swift

Le constructeur de cette vue accepte une url et une closure fournissant une phase. On attend de cette fonction closure qu’elle retourne une vue, définie ici par le type générique Content.

Pour gérer la requête, nous utilisons une classe spécifique :

Swift

La classe ImageLoader est chargée de gérer la requête. Nous utilisons la version Combine de la dataTask.

.receive permet à toutes les complétions de s’exécuter dans le bon contexte, qui est le fil principal, puisque des modifications d’interface sont prévues.

Nous publions trois variables, l’image, un booléen indiquant que la requête est en cours d’exécution et une erreur optionnelle. Ces variables sont @Published, afin que la vue puisse se mettre à jour quand leur valeur change.

Pour utiliser ImageLoader, nous l’ajoutons à la vue en tant que @ObservedObject :

Swift

Il ne reste qu’à construire le corps de la vue en fonction des différents cas :

Swift

Nous appelons la closure avec les valeurs de type AsyncImage14Phase. .success(image) si une image est publiée, .empty si la requête est en cours, et .failure(error), si ImageLoader retourne une erreur.