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 :
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 :
La vue AsyncImage
14 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 :
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.
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 :
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
:
Il ne reste qu’à construire le corps de la vue en fonction des différents cas :
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.