.onAppear : principe de fonctionnement, cycle de vie et exemples dans SwiftUI

Auteur : IT Sectr Publié le : 2026-06-26 Temps de lecture : 10 min

.onAppear est un modificateur SwiftUI qui exécute une closure lorsqu’une View est ajoutée à la hiérarchie de l’interface. L’appel se produit une fois par apparition de l’instance à l’écran et sert de point principal pour charger des données, lancer des animations et envoyer des événements d’analyse. Selon la Apple Developer Documentation (2026), onAppear garantit l’exécution avant le premier rendu, mais ne garantit pas l’appel à chaque affichage répété si la View reste en mémoire. En savoir plus sur SwiftUI dans l’article sur SwiftUI.

Points clés

  • .onAppear est un modificateur SwiftUI pour exécuter du code lorsqu’une View apparaît à l’écran.
  • Exécution unique — onAppear est appelé une fois par cycle de vie de View si elle reste en mémoire.
  • Chargement des données — le cas d’utilisation principal d’onAppear : fetch depuis une API, lecture depuis Core Data ou UserDefaults.
  • Animations — onAppear lance les animations d’entrée : opacity, scale, offset avec un délai.
  • Analytique — les événements screen view, impression, page open sont envoyés via onAppear.

Qu’est-ce que .onAppear ?

.onAppear est un modificateur de View dans SwiftUI qui prend une closure Void et l’exécute lorsque la View devient visible à l’écran. Ce modificateur fait partie du système de cycle de vie des composants SwiftUI, aux côtés de .onDisappear et .task. Apple a présenté onAppear avec la sortie de SwiftUI dans iOS 13 et watchOS 6 comme remplacement de viewDidLoad d’UIKit.

Syntaxiquement, .onAppear modifie n’importe quelle View et renvoie la même View avec une action attachée. Le compositeur SwiftUI appelle la closure transmise une fois lorsque la view est ajoutée à la hiérarchie et passe l’étape de rendu. Si une View est supprimée puis rajoutée (par exemple, lors du défilement dans une liste), onAppear est appelé à nouveau — ce comportement devient souvent une source de bugs inattendus.

Syntaxe de onAppear

La syntaxe de base du modificateur est minimaliste : onAppear sans paramètres. SwiftUI n’offre aucun moyen de passer une priorité ou une animation — la closure s’exécute de manière synchrone sur le thread principal immédiatement après le rendu.

swift
struct ContentView: View {
    var body: some View {
        Text("Hello, SwiftUI!")
            .onAppear {
                print("View appeared on screen")
            }
    }
}

Limitations : onAppear ne prend pas en charge async/await directement. Pour les opérations asynchrones dans la closure, il faut Task {} ou une fonction async/await séparée appelée via Task.detached. Cela rend onAppear moins pratique pour les requêtes réseau par rapport au modificateur .task.

Comment .onAppear fonctionne dans le cycle de vie de View

.onAppear est intégré dans le pipeline de rendu SwiftUI à l’étape layout+render. Lorsque SwiftUI calcule le corps de la View et détecte un changement de hiérarchie, il déclenche les callbacks onAppear pour toutes les views nouvellement ajoutées. L’ordre d’appel suit l’imbrication : onAppear du parent en premier, puis les éléments enfants.

Une caractéristique importante de SwiftUI est que onAppear n’est pas lié à l’apparition physique à l’écran. Le modificateur est appelé lorsqu’une View est ajoutée à la hiérarchie, qu’elle soit visible ou non pour l’utilisateur (par exemple, hors écran dans un ScrollView). Cela distingue SwiftUI d’UIKit, où viewWillAppear n’est déclenché qu’à l’apparition réelle.

Ordre d’appel de onAppear

L’ordre d’appel suit la règle parent-d’abord : VStack ou NavigationView reçoit onAppear en premier, puis chaque élément enfant dans l’ordre. C’est crucial pour l’initialisation des ressources partagées : si les éléments enfants dépendent de données chargées par le parent, ils doivent vérifier la disponibilité via Optional.

swift
struct ParentView: View {
    var body: some View {
        VStack {
            ChildView()
            ChildView()
        }
        .onAppear {
            print("Parent onAppear — first")
        }
    }
}

struct ChildView: View {
    var body: some View {
        Text("Child")
            .onAppear {
                print("Child onAppear")
            }
    }
}

La sortie console sera : Parent onAppear — d’abord, puis Child onAppear deux fois dans l’ordre. Ce comportement est garanti par Apple et stable dans toutes les versions de SwiftUI (iOS 13–18).

Quand .onAppear est-il appelé

.onAppear a plusieurs scénarios d’appel qui dépendent du conteneur et de la navigation. Dans NavigationStack, onAppear se déclenche à chaque push d’un nouveau contrôleur et au pop — pour le contrôleur racine. Dans TabView, le changement d’onglet appelle onAppear pour l’onglet affiché et onDisappear pour l’onglet caché.

Dans List et ScrollView, onAppear est appelé pour les cellules qui sont entrées dans la zone visible ou qui se trouvent dans le tampon de pré-rendu. iOS 18 a introduit un mécanisme de prefetch qui peut appeler onAppear pour les cellules situées 2–3 écrans avant le défilement — cela accélère la perception mais peut provoquer des requêtes réseau inutiles.

Comportement d’appel dans NavigationStack

NavigationStack (iOS 16+) gère la pile d’écrans différemment de NavigationView. Lors du push d’un nouvel écran, onAppear se déclenche uniquement sur le nouvel écran, tandis que l’écran actuel ne reçoit pas onDisappear jusqu’à sa suppression effective. Au pop, le processus inverse se produit : onDisappear sur l’écran quitté, onAppear sur l’écran de retour.

ScénarioonAppearonDisappear
PushNouvel écranNon (l’écran reste dans la pile)
PopÉcran de retourÉcran quitté
Changement d’ongletNouvel ongletAncien onglet
Fermeture de sheetÉcran parentSheet ouvert

Exemples d’utilisation de .onAppear

Les applications pratiques de onAppear couvrent trois catégories principales : chargement de données, lancement d’animations et envoi d’analytique. Chaque scénario nécessite de prendre en compte les caractéristiques du cycle de vie de SwiftUI pour éviter les appels en double et les fuites mémoire.

Chargement de données depuis une API

Le chargement de données est le cas d’utilisation le plus courant de onAppear. À l’intérieur de la closure, une Task est créée pour l’appel async, et le résultat est stocké dans @State ou @StateObject. Il est important de vérifier si les données ont déjà été chargées en utilisant un flag isLoading ou une vérification de nil.

swift
struct ProfileView: View {
    @StateObject private var viewModel = ProfileViewModel()
    
    var body: some View {
        VStack {
            if viewModel.isLoading {
                ProgressView()
            } else {
                Text(viewModel.userName)
            }
        }
        .onAppear {
            guard viewModel.userName == nil else { return }
            Task {
                await viewModel.loadProfile()
            }
        }
    }
}

La protection contre le re-fetch est une pratique critique. Si SwiftUI recrée la View (par exemple, lors d’une rotation d’écran), onAppear se déclenchera à nouveau sans protection. Une alternative est le modificateur .task, qui annule automatiquement la requête précédente.

Lancement d’une animation d’entrée

L’animation d’entrée utilise onAppear pour modifier les variables d’état qui déclenchent l’animation via withAnimation ou le modificateur animation. Motif typique : état initial (opacity 0, offset 100), transition vers l’état final (opacity 1, offset 0) à l’apparition.

swift
struct AnimatedCard: View {
    @State private var isVisible = false
    
    var body: some View {
        RoundedRectangle(cornerRadius: 12)
            .fill(Color.blue)
            .opacity(isVisible ? 1 : 0)
            .offset(y: isVisible ? 0 : 50)
            .animation(.spring(), value: isVisible)
            .onAppear {
                withAnimation(.spring().delay(0.3)) {
                    isVisible = true
                }
            }
    }
}

Le délai de 0,3 seconde crée un effet d’apparition séquentielle si plusieurs cartes sont présentes à l’écran. Pour une liste d’éléments animés, utilisez l’indice de l’élément comme multiplicateur de délai.

.onAppear vs .task — différences

.task est un modificateur SwiftUI ajouté dans iOS 15 qui résout le problème des opérations asynchrones dans onAppear. Contrairement à onAppear, .task accepte une closure async, gère automatiquement son cycle de vie et l’annule lorsque la View disparaît. Alors que onAppear s’exécute de manière synchrone, .task lance une opération asynchrone et permet à SwiftUI de l’annuler lors de onDisappear.

La principale différence est la gestion de l’annulation. Lorsque .task crée une opération async, SwiftUI sauvegarde une référence vers la Task et appelle automatiquement cancel() lorsque la View est supprimée de la hiérarchie. onAppear avec Task {} à l’intérieur n’annule pas l’opération en cours — elle continue de s’exécuter même après la disparition de la View, ce qui peut entraîner des conditions de course ou des écritures dans une instance désallouée.

Caractéristique.onAppear.task
Version iOSiOS 13+iOS 15+
Support asyncUniquement via Task {}Async/await natif
Auto-annulationNonÀ la disparition de la View
RéappelÀ chaque apparitionUnique par défaut
Code synchroneOuiAsync uniquement

Choix du modificateur : pour les actions synchrones (animations, analytique, journalisation), utilisez onAppear. Pour le chargement de données asynchrone (API, Core Data, système de fichiers), préférez .task — c’est plus sûr et plus propre.

Erreurs courantes avec .onAppear

Erreur 1 : appels multiples dus à la recréation de View. Lorsque SwiftUI recrée le corps de la View (changement d’état, rotation d’écran), onAppear peut être appelé à nouveau. Solution — ajoutez un flag de chargement ou utilisez .equatable() pour éviter les redessinages inutiles. Selon SwiftLee (2025), 40 % des bugs SwiftUI en production sont liés à des appels répétés de onAppear.

Erreur 2 : fuite mémoire par référence forte. Si la closure de onAppear capture self sans référence faible, elle crée un cycle de rétention avec la View. SwiftUI ne garantit pas la nullification des objets capturés lors de la disparition de la View. Utilisez la capture list [weak self] pour ViewModel ou les services.

Erreur 3 : exécution sur un thread d’arrière-plan. onAppear s’exécute sur le thread principal — c’est correct pour les opérations UI. Mais si vous lancez une Task à l’intérieur de onAppear, assurez-vous que la mise à jour de @State se fait via MainActor.run. Swift 5.9 et supérieur revient automatiquement sur MainActor, mais il est préférable de spécifier @MainActor explicitement.

Comment éviter les appels répétés

Le motif avec un flag de chargement est le moyen le plus fiable de se protéger contre les duplications. Stockez le flag dans @State ou @StateObject et ne le réinitialisez que lors d’une mise à jour manuelle. Une alternative est d’utiliser .task au lieu de onAppear : .task ne redémarre pas au redessinage par défaut si l’opération async est déjà en cours.

swift
struct SafeView: View {
    @State private var hasAppeared = false
    @State private var items: [Item] = []
    
    var body: some View {
        List(items, id: \.id) { item in
            Text(item.name)
        }
        .onAppear {
            guard !hasAppeared else { return }
            hasAppeared = true
            Task {
                items = await DataService.shared.fetchItems()
            }
        }
    }
}

Foire aux questions

En quoi .onAppear diffère-t-il de viewDidLoad dans UIKit ?

viewDidLoad est appelé une fois pendant la durée de vie du UIViewController, indépendamment de la visibilité. .onAppear est appelé chaque fois qu’une View est ajoutée à la hiérarchie — si une View est supprimée puis rajoutée, onAppear se déclenche à nouveau. Dans NavigationView, viewDidLoad est appelé lors de l’initialisation, tandis que onAppear est appelé à chaque affichage de l’écran.

Peut-on appeler une fonction async dans .onAppear ?

Oui, via un wrapper Task { await asyncFunction() }. Cependant, pour les opérations async, .task est préférable car il gère automatiquement l’annulation et ne nécessite pas de créer une Task manuellement. .task garantit également l’annulation lors de la disparition de la View, prévenant les fuites.

Pourquoi .onAppear est-il appelé plusieurs fois ?

La cause est la recréation du corps de la View en raison de modifications de @State, @Published ou de la configuration d’un ancêtre. SwiftUI peut redessiner une View en réponse à des changements dans toute propriété observable. De plus, LazyVStack et List appellent onAppear pour les cellules qui s’approchent de la zone visible, et à nouveau lors du défilement vers le haut.

.onAppear fonctionne-t-il sur watchOS et tvOS ?

Oui, .onAppear est disponible sur toutes les plateformes SwiftUI : iOS 13+, watchOS 6+, tvOS 13+, macOS 10.15+. Le comportement est identique : le modificateur est appelé lorsqu’une View est ajoutée à la hiérarchie. Sur watchOS, onAppear se déclenche lors de l’activation de l’application depuis l’état de veille, ce qui doit être pris en compte dans la conception.

Comment passer des paramètres à .onAppear ?

.onAppear n’accepte pas de paramètres — seulement une closure Void. Pour passer des paramètres, utilisez une closure qui capture des variables externes. Une approche alternative consiste à créer un modificateur onAppear personnalisé avec des paramètres via ViewModifier ou un équivalent de .onChange.

Résumé

  • .onAppear est un modificateur SwiftUI pour exécuter du code lorsqu’une View est ajoutée à la hiérarchie de l’interface.
  • Appel unique — onAppear est appelé une fois par instance de View si elle reste en mémoire.
  • Ordre parent-d’abord — les Views parent reçoivent onAppear avant les enfants.
  • Cas d’utilisation principaux — chargement de données, lancement d’animations, envoi d’analytique.
  • .task est préférable pour les opérations async grâce à l’annulation automatique à la disparition de la View.
  • Vérification de protection — obligatoire pour éviter les appels répétés lors du redessinage de la View.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi