État réseau iOS : ce que NWPathMonitor permet vraiment de vérifier

État réseau iOS : ce que NWPathMonitor permet vraiment de vérifier

État réseau iOS : ce que NWPathMonitor permet vraiment de vérifier

L’utilisateur appuie sur le bouton d’actualisation, l’application affiche « Réseau indisponible », puis une nouvelle tentative réussit quelques instants plus tard. Bien souvent, le problème ne vient pas de la couche de requêtes : l’application conditionne leur envoi à un état du chemin réseau qui n’a pas encore été actualisé. Lors du développement d’une application iOS sur un Mac cloud, on peut d’abord valider le modèle d’état avec une séquence d’événements déterministe, puis réserver le simulateur et l’appareil physique aux vérifications du comportement système. Inutile de couper sans cesse la connexion à distance pour provoquer une panne.

Séparer les indications réseau des résultats de requête

NWPathMonitor observe les chemins réseau qui répondent aux critères de surveillance. L’état .satisfied ne garantit ni que le serveur est joignable, ni que l’authentification est valide ; .requiresConnection indique qu’une connexion doit être établie, pas que l’appareil est durablement hors ligne.

Au niveau applicatif, prévoyez au moins quatre états : « inconnu », « chemin disponible », « connexion nécessaire » et « chemin indisponible ». Au premier lancement, tant qu’aucun rappel n’a été reçu, affichez un état inconnu plutôt que de considérer le réseau comme indisponible par défaut. Les délais d’attente dépassés, les échecs d’authentification et les erreurs serveur doivent relever du modèle de résultat des requêtes, sans écraser en retour l’état du chemin réseau.

L’état réseau sert à informer, pas à actionner un interrupteur général interdisant toutes les requêtes. Lorsque l’utilisateur relance une opération, c’est la requête réelle qui doit en déterminer l’issue.

Cette approche convient aux applications qui affichent un bandeau réseau ou des indications de nouvelle tentative automatique. Si une fonctionnalité se limite à envoyer une requête, il est souvent plus simple d’en traiter directement le résultat, sans ajouter de surveillance.

Construire un modèle d’état exécutable de façon autonome

Dans le terminal du Mac distant, créez NetworkStateCheck.swift et insérez l’intégralité du contenu ci-dessous. Le modèle ne dépend pas du réseau réel ; le numéro de génération permet de distinguer les différentes instances de surveillance. Cet exemple repose sur des appels séquentiels : il ne faut pas modifier directement le modèle depuis plusieurs files d’exécution en parallèle.

enum PathState: Equatable {
    case unknown, available, needsConnection, unavailable
}

struct NetworkHint {
    private(set) var generation = 0
    private(set) var state: PathState = .unknown
    private(set) var expensive = false
    private(set) var constrained = false

    mutating func restart() -> Int {
        generation += 1
        state = .unknown
        expensive = false
        constrained = false
        return generation
    }

    mutating func accept(
        generation incoming: Int,
        state next: PathState,
        expensive: Bool = false,
        constrained: Bool = false
    ) {
        guard incoming == generation else { return }
        state = next
        self.expensive = expensive
        self.constrained = constrained
    }
}

var hint = NetworkHint()
precondition(hint.state == .unknown)

let old = hint.restart()
hint.accept(generation: old, state: .available, expensive: true)
precondition(hint.state == .available && hint.expensive)

let current = hint.restart()
hint.accept(generation: old, state: .unavailable)
precondition(hint.state == .unknown)

hint.accept(generation: current, state: .needsConnection)
precondition(hint.state == .needsConnection)

hint.accept(generation: current, state: .available, constrained: true)
precondition(hint.constrained && !hint.expensive)

hint.accept(generation: current, state: .unavailable)
precondition(hint.state == .unavailable)

hint.accept(generation: current, state: .available)
precondition(hint.state == .available && !hint.constrained)

Exécutez xcrun swift NetworkStateCheck.swift. Si les vérifications réussissent, rien ne s’affiche ; en cas d’échec, le processus se termine avec un code de sortie non nul. Ce script valide le contrat d’état propre à l’application, pas le bon fonctionnement de la pile réseau du système.

Respecter l’ordre d’exécution lors du raccordement du moniteur

Dans l’adaptateur de production, importez Network, créez NWPathMonitor(), définissez d’abord pathUpdateHandler, puis appelez start(queue:). Faites correspondre les trois valeurs de NWPath.Status à l’énumération du modèle, en transmettant également isExpensive et isConstrained. Toute valeur d’énumération inconnue ajoutée à l’avenir doit être associée à l’état inconnu.

À la création du moniteur, capturez la génération courante. Vérifiez à nouveau cette génération avant de transmettre le rappel au modèle d’état. Pour relancer la surveillance, commencez par incrémenter la génération afin d’invalider les anciens événements, annulez ensuite l’ancienne instance, puis créez la nouvelle. Ne redémarrez pas une instance déjà annulée.

Le cycle de vie du moniteur et les mises à jour du modèle doivent être gérés dans un même contexte d’exécution série. Si vous utilisez le contexte d’exécution principal, vérifiez la génération après y avoir transféré le traitement du rappel. Sinon, d’anciens événements encore en attente peuvent altérer le nouvel état. Conservez aussi cet ordre lors de la publication vers l’interface : plusieurs envois asynchrones ne doivent pas écraser les états dans l’ordre inverse.

Ne vous appuyez pas uniquement sur requiredInterfaceType: .wifi pour déterminer si l’appareil dispose d’un accès réseau : cette surveillance porte sur une condition liée à une interface précise et peut ignorer d’autres chemins disponibles. N’utilisez cette initialisation que si la fonctionnalité exige réellement cette interface.

Couvrir les cas limites avec une matrice d’événements

Intégrez le script à la cible de tests unitaires du projet. Créez un modèle indépendant pour chaque cas et ajoutez au minimum les vérifications suivantes :

  • Aucun rappel après le démarrage : l’état reste inconnu et les requêtes peuvent toujours être envoyées.
  • Chemin disponible, mais échec de la requête à l’API : seule l’erreur de requête est mise à jour, sans afficher de rupture du chemin réseau.
  • Rétablissement après un chemin indisponible : le bandeau disparaît sans déclencher une seconde fois la même opération métier.
  • Réception d’un ancien événement après annulation : ni l’état ni l’indication de coût ne changent.
  • Réception répétée du même événement : l’indication reste identique et les tâches de nouvelle tentative ne s’accumulent pas.
  • Changement de l’état coûteux ou contraint : seule la stratégie de téléchargement autorisée par la logique métier est ajustée.

isExpensive ne correspond pas à un type d’interface unique, et isConstrained ne signifie pas une absence totale de réseau. Pour les transferts de fichiers volumineux, vous pouvez utiliser les règles de URLSessionConfiguration relatives aux réseaux coûteux et contraints. Ne supprimez pas silencieusement une action de l’utilisateur sur la seule base du modèle d’indication.

Distinguer les tests automatisés de la validation sur appareil

Le simulateur convient pour vérifier les bandeaux, les boutons et le raccordement du modèle d’état, mais son comportement réseau dépend de la machine hôte. Un changement d’indication dans le simulateur ne valide pas un basculement vers le réseau cellulaire. Surtout, ne désactivez pas les interfaces réseau du Mac cloud pour un test : vous risqueriez de perdre l’accès au bureau à distance.

Sur un appareil physique, complétez les tests avec les changements de réseau sans fil, le mode de données limitées et le retour au premier plan. Pour chaque scénario, consignez l’ordre des événements de chemin réseau, les changements de l’interface et les résultats des requêtes. Un refus de connexion du serveur de test et un chemin réseau indisponible sont deux scénarios distincts : conservez des éléments de validation séparés.

Livrez enfin le modèle d’état, les tests d’événements et les comptes rendus des vérifications sur appareil. Le critère de validation n’est pas que le bandeau devine toujours instantanément l’état du réseau. Il faut que les indications ne bloquent pas les requêtes à tort, qu’un ancien moniteur ne puisse pas écraser l’état d’une nouvelle session et que les actions de l’utilisateur après un échec suivent un traitement clairement défini.

Questions fréquentes

Le statut satisfied garantit-il l’accès à l’API ?

Non. Il indique un chemin conforme aux conditions de surveillance, sans vérifier le serveur, l’authentification ni la réponse. Le résultat de la requête reste déterminant.

Comment ignorer un ancien rappel après annulation ?

Incrémentez la génération dans le même contexte série avant d’annuler le moniteur. Chaque rappel conserve sa génération d’origine et seuls les événements actuels sont acceptés. Créez un nouveau moniteur au redémarrage.

Testez votre Mac à distance avec vos propres tâches.

Louez un Mac mini M4 dédié et utilisez macOS en interface graphique ou en ligne de commande. Idéal pour tester la connexion et vos flux de travail. Pour des tâches hors ligne de longue durée ou du matériel professionnel externe, comparez aussi avec l’achat.

Louer un Mac mini dédié

Louez-le un jour avant de décider si vous l’achetez.

Testez la connexion et vos tâches réelles, puis choisissez la durée d’utilisation qui vous convient.