.onDisappear est un modificateur SwiftUI qui exécute une closure lorsqu'une View est supprimée de la hiérarchie de l'interface. L'appel se produit lors de la fermeture d'un écran, du changement d'onglet, du rejet d'une fenêtre modale ou du défilement d'un élément hors de la visibilité. Selon la Documentation développeur Apple (2026), onDisappear ne garantit pas l'appel dans les scénarios de plantage ou lorsque l'application est terminée par le watchdog système. Pour en savoir plus sur SwiftUI, consultez l'article sur SwiftUI.
Points clés
.onDisappear est un modificateur de View dans SwiftUI qui prend une closure Void et l'exécute lorsque la View est supprimée de la hiérarchie. Avec .onAppear, il forme le cycle de vie complet d'un écran : apparition — travail — disparition. Apple a introduit onDisappear avec SwiftUI dans iOS 13 comme analogue de viewDidDisappear d'UIKit.
Syntactiquement, .onDisappear est identique à onAppear : il modifie n'importe quelle View et attache une closure que le rendu SwiftUI appelle lorsque la vue est supprimée. Contrairement à UIKit, où viewDidDisappear se déclenche seulement après la fin de l'animation de transition, onDisappear dans SwiftUI peut être appelé avant la fin de l'animation — au moment où la View est marquée pour suppression.
Syntaxe de base de onDisappear est aussi concise que celle de onAppear. Le modificateur ne prend aucun paramètre supplémentaire — seulement la closure, qui s'exécute de manière synchrone sur le thread principal.
struct DetailView: View {
var body: some View {
Text("Detail Screen")
.onDisappear {
print("DetailView a disparu de l'écran")
}
}
}
Mécanisme d'appel de onDisappear est l'opposé de onAppear : les éléments enfants reçoivent onDisappear en premier, puis le parent. Cette règle child-first garantit que les ressources enfant sont libérées avant que les ressources parent ne soient libérées. Si un élément enfant dépend des données parent, il doit pouvoir se terminer correctement sans le contexte parent.
SwiftUI appelle onDisappear lorsque la View est supprimée du graphe de rendu. Les déclencheurs incluent : pop de NavigationStack, changement de TabView, rejet de modal (sheet/fullScreenCover) ou une View rendue conditionnellement (if/switch). Dans List et ScrollView, onDisappear est appelé lorsqu'une cellule défile au-delà du tampon de préchargement.
Ordre child-first signifie que si un VStack a trois View enfants, onDisappear est appelé d'abord pour chaque enfant dans l'ordre inverse, puis pour le parent. Ceci est critique pour un nettoyage approprié : les minuteries enfants sont annulées avant que le ViewModel parent ne libère les ressources partagées.
struct ParentView: View {
var body: some View {
VStack {
ChildView(id: "A")
ChildView(id: "B")
}
.onDisappear {
print("Parent onDisappear — dernier")
}
}
}
struct ChildView: View {
let id: String
var body: some View {
Text("Child \(id)")
.onDisappear {
print("Child \(id) onDisappear")
}
}
}
Sortie console : Child B onDisappear, Child A onDisappear, Parent onDisappear — dernier. L'ordre inverse par rapport à onAppear garantit une chaîne de nettoyage correcte.
Scénarios d'appel de onDisappear dépendent du type de conteneur. Dans NavigationStack, onDisappear se déclenche lors du pop-to-root, du pop-back normal ou du rejet d'écran par balayage (interactivePopGestureRecognizer). Dans TabView, changer d'onglet appelle onDisappear pour l'onglet masqué et onAppear pour l'onglet affiché — les deux modificateurs se déclenchent presque simultanément.
Dans Sheet et fullScreenCover, onDisappear est appelé lors du rejet programmatique (via @Environment(\.dismiss)) ou d'un geste de balayage vers le bas. Un détail important : si un sheet a été ouvert mais que l'utilisateur a changé d'application, onDisappear n'est PAS appelé jusqu'à la fermeture effective.
| Scénario | onDisappear appelé | Note |
|---|---|---|
| Pop dans NavigationStack | Oui | Immédiatement après l'animation |
| Changement d'onglet TabView | Oui | Onglet actuel |
| Rejet de sheet | Oui | Avant la fin de l'animation |
| Défilement dans List | Oui | Cellule sortie de la zone de préchargement |
| Minimisation de l'application | Non | Aucune garantie d'appel |
| Plantage/watchdog kill | Non | Pas appelé |
Cas d'utilisation principaux de onDisappear sont le nettoyage des ressources, la sauvegarde d'état et le suivi. Contrairement à onAppear, les tâches de onDisappear s'exécutent à la sortie et ne nécessitent pas de vérification de duplication car la View disparaît une seule fois.
Sauvegarde d'état dans onDisappear est particulièrement utile pour les formulaires où les données doivent être sauvegardées en quittant l'écran. Les minuteries et les abonnements Combine sont annulés dans onDisappear pour éviter les fuites lors du retour à l'écran.
struct FormView: View {
@State private var draftText = ""
@State private var timer: Timer?
var body: some View {
TextField("Enter text", text: $draftText)
.onAppear {
timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in
saveDraft()
}
}
.onDisappear {
timer?.invalidate()
timer = nil
saveDraft()
}
}
private func saveDraft() {
UserDefaults.standard.set(draftText, forKey: "draft")
}
}
Annulation du minuteur dans onDisappear empêche l'exécution de code après que l'écran est déjà fermé. Sans annulation, le minuteur pourrait tenter de mettre à jour @State qui n'appartient plus à la View actuelle, provoquant un avertissement d'exécution.
Temps de séjour sur un écran est un scénario de suivi classique. Enregistrez le temps dans onAppear, calculez la différence dans onDisappear et envoyez un événement analytique avec la durée de la session.
struct TrackedView: View {
@State private var appearTime: Date?
var body: some View {
Text("Tracked Screen")
.onAppear {
appearTime = Date()
Analytics.shared.logEvent("screen_view", params: ["screen": "TrackedView"])
}
.onDisappear {
if let start = appearTime {
let duration = Date().timeIntervalSince(start)
Analytics.shared.logEvent("screen_close", params: [
"screen": "TrackedView",
"duration_ms": Int(duration * 1000)
])
}
}
}
}
La différence clé entre onDisappear et onAppear est l'ordre d'appel et les garanties d'exécution. onAppear est appelé lorsqu'une View est ajoutée à la hiérarchie et peut être rappelé lors de la recréation. onDisappear est appelé lors de la suppression et n'est garanti de se déclencher qu'en fermeture normale, pas dans les scénarios de plantage.
Selon la WWDC 2024, Apple recommande de traiter onDisappear comme un point de nettoyage, pas comme un point de validation de données. Les données critiques (paiements, inscriptions) doivent être sauvegardées en temps réel, pas au moment de la disparition de la View, car onDisappear n'est pas garanti lorsque l'application est minimisée.
| Caractéristique | .onAppear | .onDisappear |
|---|---|---|
| Moment d'appel | View ajoutée à la hiérarchie | View retirée de la hiérarchie |
| Ordre | Parent-first | Child-first |
| Garantie | Élevée | Pas en cas de plantage |
| Tâche principale | Initialisation | Nettoyage |
| Appel répété | Lors de la recréation de View | Une fois par disparition |
Recommandation : utilisez onDisappear uniquement pour le nettoyage non critique et le suivi. Pour la persistance des données, utilisez scenePhase ou les notifications applicationWillTerminate dans AppDelegate.
Scénario 1 : lecture type YouTube. Sur l'écran des détails de la vidéo, onDisappear sauvegarde la position de lecture dans UserDefaults. À la réouverture, onAppear restaure la position depuis UserDefaults, créant une expérience de visionnage continue.
Scénario 2 : annuler un abonnement Combine. Si un ViewModel utilise des publishers Combine, onDisappear annule l'abonnement via cancellable?.cancel(). Cela empêche les mises à jour de l'UI après avoir quitté l'écran, ce qui est particulièrement important pour les listes avec pagination et les requêtes de recherche.
Scénario 3 : fermer WebSocket. Dans les applications avec connexions en temps réel (messageries, flux de cotations), onDisappear ferme la connexion WebSocket pour économiser la batterie et les données. La reconnexion se produit dans onAppear lors du retour à l'écran.
WebSocket est une ressource typique qui doit être fermée en quittant l'écran. Dans l'exemple ci-dessous, onDisappear déconnecte le socket et onAppear le reconnecte, offrant des économies de données significatives pour les applications avec plusieurs écrans.
struct ChatView: View {
@StateObject private var socket = WebSocketManager()
var body: some View {
ChatListView(messages: socket.messages)
.onAppear {
socket.connect()
}
.onDisappear {
socket.disconnect()
}
}
}
Important : lors du changement d'onglets TabView, onDisappear de l'onglet actuel et onAppear de l'onglet suivant se déclenchent presque simultanément. Pour WebSocket, cela peut créer un cycle déconnexion-reconnexion qui génère une charge inutile. La solution est d'utiliser un délai ou de vérifier si le socket est nécessaire sur l'écran suivant.
Questions fréquentes
Oui, .onDisappear ne garantit pas l'appel en cas de plantage de l'application (crash, watchdog kill), de minimisation de l'application sans fermer l'écran ou de scénarios système où l'application est terminée en arrière-plan. Pour les données critiques, utilisez scenePhase ou applicationWillTerminate.
.onDisappear se déclenche lorsqu'une View est retirée de la hiérarchie — un rappel local pour un écran spécifique. .scenePhase (via @Environment(\.scenePhase)) se déclenche lorsque l'état de l'application entière change : active, inactive, background. Utilisez onAppear+onDisappear pour le suivi du temps passé à l'écran et scenePhase pour la persistance de l'état global.
La cause est le changement rapide d'onglets ou le push/pop répété du même écran. SwiftUI peut créer une nouvelle instance de View, supprimer l'ancienne, en créer une nouvelle — chaque fois appelant onDisappear et onAppear. Vérifiez si vous utilisez .id(), .equatable() ou recréez la View dans le body parent.
Oui, .onDisappear est entièrement pris en charge sur macOS (10.15+) avec le même comportement : appelé lors de la fermeture de la fenêtre, de la suppression d'un panneau de vue divisée ou du rejet d'un modal. Sur macOS, onDisappear est également appelé lors du masquage de la fenêtre (pas seulement lors de la fermeture), ce qui est important à considérer pour les applications macOS.
Enregistrez une référence à URLSessionTask dans @State et appelez task.cancel() dans onDisappear. Alternativement, utilisez le modificateur .task qui annule automatiquement l'opération asynchrone lorsque la View disparaît. .task est préféré pour toutes les opérations asynchrones, y compris URLSession.
Résumé
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.
Lisez aussi