Un collègue me montre son app de réservation de covoiturage : sur son iPhone 15 Pro, l'écran d'accueil met une bonne seconde et demie à afficher les trajets disponibles. « C'est le réseau, forcément », me dit-il. J'ai lancé un petit test réseau : la requête elle-même revenait en 180 ms. Le reste, un peu plus d'une seconde, se passait dans son code. Ce n'est pas le Wi-Fi. C'est l'app.
La confusion entre « mon téléphone rame » et « mon app iOS a de la latence » est le point de départ de presque tous mes audits. Et c'est exactement pour ça qu'on trouve si peu de contenu utile sur le sujet : les articles parlent de redémarrer l'iPhone, alors que le vrai problème se joue dans URLSession, dans le rendu SwiftUI et dans le démarrage à froid.
Points clés à retenir
- La latence d'une app iOS se décompose en trois postes distincts : réseau, rendu, démarrage. Les mélanger, c'est chercher à l'aveugle.
- Avant de toucher au code, mesurez avec les signposts et Instruments, sinon vous optimisez au hasard.
- Réduire le nombre de round-trips réseau fait souvent plus d'effet qu'un refactor complet.
- Un cold start au-delà de 400 ms se ressent immédiatement comme une app « lente ».
- Le Wi-Fi capté comme bouc émissaire : vérifiez toujours la durée côté client avant d'accuser l'infra.
Comment réduire la latence d'une application mobile iOS : d'abord identifier la vraie coupable
Sur à peu près une dizaine d'audits que j'ai menés ces deux dernières années, la répartition est étonnamment stable : dans environ six cas sur dix, le temps perdu venait du rendu ou de l'initialisation, pas du réseau. Le réseau était le coupable désigné, jamais le coupable réel.
Pourquoi ? Parce que c'est le plus facile à accuser. L'utilisateur est en 4G dans le métro, l'écran met du temps à s'actualiser, on se dit « c'est la connexion ». Sauf que l'app affiche aussi une liste mal dédifférenciée, recalcule une image en pleine décodage sur le thread principal, ou relance une requête qu'elle avait déjà faite trente secondes plus tôt.
Les trois postes à mesurer séparément
Vous devez absolument distinguer :
- La latence réseau : temps entre l'émission de la requête et la réception de la réponse complète.
- La latence de rendu : temps entre les données disponibles et les pixels affichés à l'écran, hors premier frame.
- La latence de démarrage : cold start (app non lancée) et warm start (app en arrière-plan), qui n'ont pas les mêmes coûts.
Un chiffre qui vaut son pesant de café : dans mon app de suivi de dépenses perso, le cold start tournait autour de 1,2 s avant optimisation. Les utilisateurs en test me disaient « c'est lent à ouvrir », pas « c'est lent à charger ». La perception se joue au démarrage, pas au milieu de l'écran.
Mesurer avant de toucher quoi que ce soit
La règle que je me répète à chaque fois : pas d'optimisation sans trace. Concrètement, j'instrumente les points chauds avec os_signpost, puis je lis le résultat dans Instruments via le template Time Profiler couplé aux signposts. Une trentaine de minutes de pose, et vous avez une cartographie honnête.
Xcode Organizer et MetricKit complètent bien le tableau pour les métriques de production, notamment les distributions de durée de lancement et de hitches de rendu. Car vos tests sur simulateur mentent : le simulateur ne mesure ni le vrai disque ni le vrai GPU de l'iPhone.
La latence réseau : le chantier le plus rentable sur une app iOS
Un collègue avait une stratégie de cache « au cas où » : aucune. Chaque pull-to-refresh relançait trois requêtes, dont deux strictement identiques. En branchant un simple cache HTTP côté client, environ 40 % des requêtes ont disparu et la sensation de fluidité a changé du jour au lendemain, sans une seule ligne côté serveur.
HTTP/2 et HTTP/3 : le multiplexage n'est pas un détail
Si votre backend est encore en HTTP/1.1 avec des connexions séparées par requête, vous payez un handshake TLS à chaque fois. Le multiplexage HTTP/2 permet à plusieurs requêtes de partager une connexion. Passer en HTTP/3 ajoute une négociation plus rapide sur les réseaux instables, ce qui compte sur mobile. Attention toutefois : si votre serveur n'est pas correctement configuré pour HTTP/3, vous perdez plus que vous ne gagnez. J'ai vu un projet où l'activation prématurée a fait augmenter la latence moyenne de 15 %, le temps que l'équipe infra corrige la config.
Mise en cache et préchargement : les gains faciles
Sur une app iOS, trois leviers se rentabilisent vite :
- Configurer une URLCache avec une politique de cache explicite, au lieu du comportement par défaut qui ignore souvent les en-têtes.
- Précharger les données dès l'écran précédent, quand le parcours utilisateur le justifie.
- Réduire la taille des payloads (compression, pagination, suppression des champs inutiles).
Un exemple concret sur une app de catalogue produits : en paginant à 20 items au lieu de charger la liste entière et en compressant les réponses JSON, la taille moyenne des réponses passe d'environ 800 Ko à 180 Ko. Résultat : le premier rendu utile arrive nettement plus vite sur les connexions moyennes, et le ressenti change.
Timeouts et retry : à configurer avec discernement
Un timeout trop long donne l'impression d'une app figée. Un retry sauvage multiplie les requêtes en cas de panne et aggrave la latence perçue. J'utilise des timeouts courts (autour de 10-15 s pour une requête interactive) avec une stratégie de backoff exponentiel côté client, et un seul retry sur les erreurs transitoires.
La latence de rendu : là où SwiftUI et UIKit se piègent
Les écrans qui « sautent » ou qui se reconstruisent en boucle : c'est rarement la faute du réseau. C'est souvent un état mal découpé qui invalide un sous-arbre entier à chaque changement.
Éviter les invalidations inutiles en SwiftUI
En SwiftUI, le piège classique : une vue parente dont l'état change souvent, qui redessine des enfants qui n'ont pourtant pas bougé. Les gains viennent de la découpe : isoler les sous-vues, utiliser @State local plutôt que d'élever tout au parent, et ne pas refaire un ForEach avec des identités instables. Sur l'un de mes projets, une liste de messages avec des identités basées sur l'index générait un diff inutile à chaque nouveau message : en passant sur un identifiant stable, le nombre de recompositions a chuté, et le défilement est devenu net.
Décodage d'images hors du thread principal
Les images sont un coupable sous-estimé. Une image haute résolution décodée sur le thread principal en plein scroll, et l'app se met à saccader. La solution est mécanique : décoder en amont, redimensionner à la taille d'affichage réelle, et laisser le décodage asynchrone. Ça ne réduit pas la latence réseau d'un millimètre, mais la latence perçue d'un cran net.
Comparatif des leviers d'optimisation sur une app iOS
| Levier | Effort de mise en place | Impact sur la latence perçue | Risque principal |
|---|---|---|---|
| Cache HTTP (URLCache) | Faible | Élevé sur les écrans de consultation | Données périmées affichées si la politique est mal réglée |
| Passage HTTP/2 ou HTTP/3 | Moyen (souvent côté infra) | Moyen à élevé sur réseaux mobiles | Configuration serveur mal faite : régression possible |
| Découpe des vues SwiftUI | Moyen | Élevé sur les listes et le scroll | Refactor lourd sur une base ancienne |
| Démarrage à froid réduit | Variable | Très élevé sur la perception d'« app lente » | Peu de gains si dépendances lourdes en chargement |
| Préchargement intelligent | Moyen | Bon sur les parcours répétés | Consommation réseau et batterie en hausse |
« Mon iPhone est lent depuis la mise à jour » : ce qu'il faut vérifier avant d'accuser votre app
Vous avez sans doute déjà entendu cette phrase d'un utilisateur, ou vous l'avez pensé vous-même après une mise à jour iOS. Il y a un vrai sujet ici : une nouvelle version d'iOS peut modifier les performances de certaines API, notamment côté rendu et démarrage, et une app mal préparée peut se retrouver à faire du travail inutile qu'elle ne faisait pas avant.
Mon iPhone est lent depuis la mise à jour iOS : est-ce vraiment l'app ?
Pas forcément. Il faut d'abord distinguer ce qui relève de l'appareil (stockage saturé, batterie vieillissante, tâches de fond) de ce qui relève de l'app. Une méthode simple : comparez votre app à une autre app équivalente sur le même téléphone. Si tout est lent, c'est l'appareil. Si seule la vôtre rame, c'est votre code. J'ai déjà vu un utilisateur signaler une lenteur qui n'existait que sur son appareil, à cause d'une capacité de stockage quasi pleine. Redémarrage, mise à jour, nettoyage, et le problème s'est évaporé.
Mon iPhone est lent en Wi-Fi : ça vient de la connexion ou de l'app ?
La réponse est mesurable : si une requête réseau met plus de 200 ms côté client alors que le débit est correct, le problème n'est probablement pas le Wi-Fi. Testez avec un endpoint local ou un endpoint public simple. Si celui-ci répond vite et que votre app non, c'est votre pile réseau ou votre serveur. Ne cherchez pas midi à quatorze heures.
iPad lent sur Internet et en Wi-Fi : un cas à part ?
Les iPad récents ont des écrans de grande taille, et une app qui n'optimise pas son rendu va se voir davantage sur iPad que sur iPhone, simplement parce que la surface de pixels à rafraîchir est plus grande. La même latence de rendu, moins perceptible sur un iPhone, devient flagrante sur un iPad. Ce n'est pas le Wi-Fi : c'est le coût du rendu qui grimpe avec la résolution.
La checklist que j'applique, dans cet ordre
Un dernier point, très concret, pour ne pas tourner en rond. Voici l'ordre que j'utilise, et il n'est pas négociable :
- Instrumenter les trois postes (réseau, rendu, démarrage) avec des signposts. Sans données, rien.
- Comparer avec un appareil réel, jamais seulement le simulateur.
- Optimiser le réseau en premier si les requêtes dépassent 200 ms côté client.
- Puis le rendu : découpe des vues, images décodées en amont, identités stables.
- Enfin le démarrage : dépendances, chargements synchrones, initialisations paresseuses.
Je me suis planté une fois en inversant l'ordre : j'ai passé deux semaines à refondre le rendu d'un écran, alors que la vraie latence venait d'une requête bloquante au lancement. Leçon retenue : mesurer, toujours, avant d'optimiser.
La latence d'une app iOS n'est jamais un seul problème. C'est un empilement de petites décisions, prises parfois des mois plus tôt, qui s'additionnent. La bonne nouvelle, c'est qu'aucune d'elles n'est irréversible. La moins bonne, c'est que sans mesure, vous corrigez le mauvais endroit avec beaucoup d'application.