.onDisappear: αρχή λειτουργίας και εφαρμογή στο SwiftUI

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-06-26 Χρόνος ανάγνωσης: 10 λεπ

.onDisappear — ένας τροποποιητής SwiftUI που εκτελεί ένα closure όταν ένα View αφαιρείται από την ιεραρχία διεπαφής. Η κλήση γίνεται κατά το κλείσιμο της οθόνης, την αλλαγή καρτέλας, το dismiss modal παραθύρου ή το scroll ενός στοιχείου εκτός ορατής περιοχής. Σύμφωνα με το Apple Developer Documentation (2026), το onDisappear δεν εγγυάται κλήση σε σενάρια έκτακτης τερματισμού ή καταστροφής της εφαρμογής από system-watchdog. Διαβάστε περισσότερα για το SwiftUI στο υλικό για το SwiftUI.

Κύρια σημεία

  • .onDisappear — τροποποιητής SwiftUI για εκτέλεση κώδικα όταν ένα View εξαφανίζεται.
  • Συμμετρία — το onDisappear είναι ζεύγος του onAppear και καλείται με αντίστροφη σειρά.
  • Καθαρισμός πόρων — το κύριο σενάριο: ακύρωση χρονομέτρων, κλείσιμο συνδέσεων, αποθήκευση κατάστασης.
  • Αναλυτικά — μέσω onDisappear αποστέλλονται συμβάντα screen close, dwell time, session end.
  • Έλλειψη εγγύησης — το onDisappear δεν καλείται σε έκτακτο τερματισμό της εφαρμογής.

Τι είναι το .onDisappear;

.onDisappear — ένας τροποποιητής View στο SwiftUI που δέχεται ένα Void closure και το εκτελεί όταν το View αφαιρείται από την ιεραρχία. Μαζί με το .onAppear σχηματίζει τον πλήρη κύκλο ζωής της οθόνης: εμφάνιση — λειτουργία — εξαφάνιση. Η Apple εισήγαγε το onDisappear μαζί με την κυκλοφορία του SwiftUI στο iOS 13 ως ανάλογο του viewDidDisappear από το UIKit.

Συντακτικά .onDisappear είναι πανομοιότυπο με το onAppear: τροποποιεί οποιοδήποτε View και επισυνάπτει ένα closure που καλείται από το στοιχείο SwiftUI κατά την αφαίρεση της προβολής. Σε αντίθεση με το UIKit, όπου το viewDidDisappear ενεργοποιείται μόνο μετά την ολοκλήρωση του animation μετάβασης, το onDisappear στο SwiftUI μπορεί να κληθεί πριν από την ολοκλήρωση του animation — τη στιγμή που το View επισημαίνεται για αφαίρεση.

Σύνταξη onDisappear

Βασική σύνταξη του onDisappear είναι εξίσου συνοπτική με του onAppear. Ο τροποποιητής δεν δέχεται πρόσθετες παραμέτρους — μόνο το closure που εκτελείται σύγχρονα στο κύριο νήμα.

swift
struct DetailView: View {
    var body: some View {
        Text("Οθόνη Λεπτομερειών")
            .onDisappear {
                print("Το DetailView εξαφανίστηκε από την οθόνη")
            }
    }
}

Πώς λειτουργεί το .onDisappear

Μηχανισμός κλήσης του onDisappear είναι αντίθετος του onAppear: πρώτα τα θυγατρικά στοιχεία λαμβάνουν onDisappear, μετά ο γονέας. Αυτός ο κανόνας child-first εγγυάται ότι οι πόροι των θυγατρικών στοιχείων απελευθερώνονται πριν από τους πόρους του γονέα. Εάν ένα θυγατρικό στοιχείο εξαρτάται από δεδομένα του γονέα, πρέπει να μπορεί να τερματιστεί σωστά χωρίς το περιβάλλον του γονέα.

SwiftUI καλεί το onDisappear τη στιγμή που το View εξαιρείται από το γράφημα απόδοσης. Ενεργοποιητής μπορεί να είναι: pop από NavigationStack, αλλαγή TabView, dismiss modal παραθύρου (sheet/fullScreenCover), αλλαγή υπό όρους εμφανιζόμενου View (if/switch). Σε List και ScrollView το onDisappear καλείται όταν ένα κελί γίνεται scroll εκτός του προσωρινού buffer prefetch.

Σειρά κλήσης child-first

Σειρά child-first σημαίνει ότι αν υπάρχουν τρία θυγατρικά View σε ένα VStack, το onDisappear θα κληθεί πρώτα για κάθε παιδί με αντίστροφη σειρά, μετά για τον γονέα. Αυτό είναι κρίσιμο για σωστό καθαρισμό: τα θυγατρικά χρονόμετρα ακυρώνονται προτού το ViewModel του γονέα απελευθερώσει κοινόχρηστους πόρους.

swift
struct ParentView: View {
    var body: some View {
        VStack {
            ChildView(id: "A")
            ChildView(id: "B")
        }
        .onDisappear {
            print("Parent onDisappear — τελευταίο")
        }
    }
}

struct ChildView: View {
    let id: String
    var body: some View {
        Text("Παιδί \(id)")
            .onDisappear {
                print("Παιδί \(id) onDisappear")
            }
    }
}

Έξοδος κονσόλας: Child B onDisappear, Child A onDisappear, Parent onDisappear — τελευταίο. Η αντίστροφη σειρά σε σύγκριση με το onAppear εγγυάται μια σωστή αλυσίδα απελευθέρωσης.

Πότε καλείται το .onDisappear

Σενάρια κλήσης του onDisappear εξαρτώνται από τον τύπο του περιέκτη. Στο NavigationStack το onDisappear ενεργοποιείται σε pop-to-root, συνηθισμένο pop-back ή αφαίρεση οθόνης με χειρονομία σύρσιμου (interactivePopGestureRecognizer). Στο TabView η αλλαγή καρτέλας ενεργοποιεί onDisappear για την κρυφή και onAppear για την εμφανιζόμενη — και οι δύο τροποποιητές ενεργοποιούνται σχεδόν ταυτόχρονα.

Σε Sheet και fullScreenCover το onDisappear καλείται σε προγραμματισμένο dismiss (μέσω @Environment(\.dismiss)) ή χειρονομία σύρσιμου προς τα κάτω. Σημαντικό χαρακτηριστικό: αν το sheet ήταν ανοιχτό αλλά ο χρήστης άλλαξε εφαρμογή, το onDisappear ΔΕΝ καλείται μέχρι το πραγματικό κλείσιμο.

ΣενάριοonDisappear καλείταιΣημείωση
Pop στο NavigationStackΝαιΑμέσως μετά το animation
Αλλαγή καρτέλας TabViewΝαιΤρέχουσα καρτέλα
Dismiss sheetΝαιΠριν την ολοκλήρωση animation
Scroll σε ListΝαιΚελί βγήκε από ζώνη prefetch
Ελαχιστοποίηση εφαρμογήςΌχιΚαμία εγγύηση κλήσης
Crash/watchdog killΌχιΔεν καλείται

Παραδείγματα .onDisappear

Κύρια σενάρια του onDisappear — καθαρισμός πόρων, αποθήκευση κατάστασης και παρακολούθηση. Σε αντίθεση με το onAppear, οι εργασίες onDisappear εκτελούνται κατά την έξοδο και δεν απαιτούν έλεγχο διπλοτύπου, καθώς το View εξαφανίζεται μία φορά.

Αποθήκευση κατάστασης και ακύρωση χρονομέτρων

Αποθήκευση κατάστασης στο onDisappear είναι ιδιαίτερα χρήσιμη για φόρμες όπου τα δεδομένα πρέπει να αποθηκεύονται κατά την έξοδο από την οθόνη. Τα χρονόμετρα και οι συνδρομές Combine ακυρώνονται στο onDisappear για να αποφευχθούν διαρροές μνήμης κατά την επιστροφή στην οθόνη.

swift
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")
    }
}

Ακύρωση χρονομέτρου στο onDisappear αποτρέπει την εκτέλεση κώδικα μετά το κλείσιμο της οθόνης. Χωρίς ακύρωση, το χρονόμετρο μπορεί να προσπαθήσει να ενημερώσει ένα @State που δεν ανήκει πλέον στο τρέχον View, προκαλώντας προειδοποίηση χρόνου εκτέλεσης.

Παρακολούθηση χρόνου στην οθόνη

Διάρκεια παραμονής στην οθόνη — ένα κλασικό σενάριο παρακολούθησης. Καταγράφουμε τον χρόνο στο onAppear, υπολογίζουμε τη διαφορά στο onDisappear και στέλνουμε ένα αναλυτικό συμβάν με τη διάρκεια συνεδρίας.

swift
struct TrackedView: View {
    @State private var appearTime: Date?
    
    var body: some View {
        Text("Παρακολουθούμενη Οθόνη")
            .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)
                    ])
                }
            }
    }
}

.onDisappear vs .onAppear — διαφορές

Βασική διαφορά του onDisappear από το onAppear — η σειρά κλήσης και οι εγγυήσεις ενεργοποίησης. Το onAppear καλείται όταν το View προστίθεται στην ιεραρχία και έχει την ιδιότητα επανακλήσης κατά την αναδημιουργία. Το onDisappear καλείται κατά την αφαίρεση και εγγυημένα λειτουργεί μόνο σε κανονικό κλείσιμο, αλλά όχι σε σενάρια έκτακτης ανάγκης.

Σύμφωνα με το WWDC 2024, η Apple συνιστά να θεωρείται το onDisappear ως σημείο καθαρισμού, όχι ως σημείο αποθήκευσης δεδομένων. Τα κρίσιμα σημαντικά δεδομένα (πληρωμές, εγγραφές) πρέπει να αποθηκεύονται σε πραγματικό χρόνο, όχι τη στιγμή εξαφάνισης του View, επειδή το onDisappear δεν εγγυάται κλήση κατά την ελαχιστοποίηση της εφαρμογής.

Χαρακτηριστικό.onAppear.onDisappear
Στιγμή κλήσηςΠροσθήκη View στην ιεραρχίαΑφαίρεση View από την ιεραρχία
ΣειράParent-firstChild-first
ΕγγύησηΥψηλήΌχι σε έκτακτο τερματισμό
Κύρια εργασίαΑρχικοποίησηΚαθαρισμός
ΕπανακλήσηΣε αναδημιουργία ViewΜία φορά ανά εξαφάνιση

Σύσταση: χρησιμοποιείτε το onDisappear μόνο για μη κρίσιμο καθαρισμό και παρακολούθηση. Για αποθήκευση δεδομένων χρησιμοποιείτε scenePhase ή ειδοποιήσεις applicationWillTerminate στο AppDelegate.

Τυπικά σενάρια εφαρμογής

Σενάριο 1: φόρτωση τύπου YouTube. Στην οθόνη λεπτομερειών βίντεο το onDisappear αποθηκεύει τη θέση αναπαραγωγής στο UserDefaults. Κατά το εκ νέου άνοιγμα, το onAppear επαναφέρει τη θέση από το UserDefaults, δίνοντας εφέ συνεχούς παρακολούθησης.

Σενάριο 2: ακύρωση συνδρομής Combine. Εάν το ViewModel χρησιμοποιεί εκδότες Combine, το onDisappear ακυρώνει τη συνδρομή μέσω cancellable?.cancel(). Αυτό αποτρέπει την ενημέρωση του UI μετά την έξοδο από την οθόνη, κάτι που είναι ιδιαίτερα σημαντικό για λίστες με σελιδοποίηση και ερωτήματα αναζήτησης.

Σενάριο 3: κλείσιμο WebSocket. Σε εφαρμογές με συνδέσεις πραγματικού χρόνου (messengers, ροές τιμών) το onDisappear κλείνει τη σύνδεση WebSocket για εξοικονόμηση μπαταρίας και κίνησης. Το εκ νέου άνοιγμα γίνεται στο onAppear κατά την επιστροφή στην οθόνη.

Κλείσιμο WebSocket στο onDisappear

WebSocket — ένας τυπικός πόρος που πρέπει να κλείνει κατά την έξοδο από την οθόνη. Στο παρακάτω παράδειγμα το onDisappear αποσυνδέει το socket και το onAppear το επανασυνδέει, προσφέροντας σημαντική εξοικονόμηση κίνησης για εφαρμογές με πολλές οθόνες.

swift
struct ChatView: View {
    @StateObject private var socket = WebSocketManager()
    
    var body: some View {
        ChatListView(messages: socket.messages)
            .onAppear {
                socket.connect()
            }
            .onDisappear {
                socket.disconnect()
            }
    }
}

Σημαντικό: κατά την εναλλαγή μεταξύ καρτελών TabView, το onDisappear της τρέχουσας καρτέλας και το onAppear της επόμενης ενεργοποιούνται σχεδόν ταυτόχρονα. Για WebSocket αυτό μπορεί να οδηγήσει σε έναν κύκλο disconnect-connect που δημιουργεί πρόσθετο φορτίο. Λύση — χρήση καθυστέρησης ή έλεγχος αν το socket χρειάζεται στην επόμενη οθόνη.

Συχνές Ερωτήσεις

Μπορεί το .onDisappear να μην κληθεί;

Ναι, το .onDisappear δεν εγγυάται κλήση σε έκτακτο τερματισμό της εφαρμογής (crash, watchdog kill), ελαχιστοποίηση της εφαρμογής χωρίς κλείσιμο οθόνης ή σενάριο συστήματος όπου η εφαρμογή καταστρέφεται στο παρασκήνιο. Για κρίσιμα σημαντικά δεδομένα χρησιμοποιείτε scenePhase ή applicationWillTerminate.

Πώς να ξεχωρίσουμε το .onDisappear από το .scenePhase;

.onDisappear ενεργοποιείται κατά την αφαίρεση του View από την ιεραρχία — ένα τοπικό callback για μια συγκεκριμένη οθόνη. .scenePhase (μέσω @Environment(\.scenePhase)) ενεργοποιείται όταν αλλάζει η κατάσταση ολόκληρης της εφαρμογής: active, inactive, background. Για παρακολούθηση χρόνου στην οθόνη χρησιμοποιήστε onAppear+onDisappear, για αποθήκευση καθολικής κατάστασης — scenePhase.

Γιατί το .onDisappear καλείται πολλές φορές στη σειρά;

Η αιτία — γρήγορη εναλλαγή μεταξύ καρτελών ή επαναλαμβανόμενο push/pop της ίδιας οθόνης. Το SwiftUI μπορεί να δημιουργήσει ένα νέο στιγμιότυπο View, να αφαιρέσει το παλιό, να δημιουργήσει ξανά — κάθε φορά ενεργοποιώντας onDisappear και onAppear. Ελέγξτε αν χρησιμοποιείτε .id(), .equatable() ή αν αναδημιουργείτε το View στο σώμα του γονέα.

Λειτουργεί το .onDisappear στο SwiftUI σε macOS;

Ναι, το .onDisappear υποστηρίζεται πλήρως σε macOS (10.15+) με την ίδια συμπεριφορά: καλείται κατά το κλείσιμο παραθύρου, αφαίρεση πίνακα split view ή dismiss modal παραθύρου. Σε macOS το onDisappear καλείται επίσης κατά την απόκρυψη παραθύρου (hide), όχι μόνο κατά το κλείσιμο, κάτι που είναι σημαντικό για εφαρμογές macOS.

Πώς να ακυρώσουμε URLSessionTask στο .onDisappear;

Αποθηκεύστε την αναφορά στο URLSessionTask σε @State και καλέστε task.cancel() στο onDisappear. Εναλλακτικά, χρησιμοποιήστε τον τροποποιητή .task που ακυρώνει αυτόματα την async λειτουργία κατά την εξαφάνιση του View. Το .task είναι προτιμότερο για όλες τις async λειτουργίες, συμπεριλαμβανομένου του URLSession.

Σύνοψη

  • .onDisappear — ζεύγος τροποποιητής του onAppear για καθαρισμό πόρων και παρακολούθηση κατά την εξαφάνιση View.
  • Σειρά child-first — τα θυγατρικά View λαμβάνουν onDisappear νωρίτερα από τον γονέα για σωστή αλυσίδα απελευθέρωσης.
  • Καμία εγγύηση κλήσης — σε crash, ελαχιστοποίηση ή τερματισμό συστήματος το onDisappear μπορεί να μη λειτουργήσει.
  • Κύρια σενάρια — ακύρωση χρονομέτρων, κλείσιμο WebSocket, αποθήκευση κατάστασης, παρακολούθηση διάρκειας.
  • Αναλυτικά — το onDisappear στέλνει συμβάντα screen_close με υπολογισμό dwell time μέσω Date().timeIntervalSince.
  • Για async λειτουργίες — χρησιμοποιήστε .task αντί για onDisappear με Task {}, καθώς το .task ακυρώνει αυτόματα τα αιτήματα.

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης