.onDisappear: หลักการทำงานและการใช้งานใน SwiftUI

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-26 เวลาอ่าน: 10 นาที

.onDisappear คือตัวปรับแต่ง SwiftUI ที่ดำเนินการ closure เมื่อ View ถูกลบออกจากลำดับชั้นของอินเทอร์เฟซ การเรียกเกิดขึ้นเมื่อปิดหน้าจอ เปลี่ยนแท็บ ปิดหน้าต่างโมดอล หรือเลื่อนองค์ประกอบออกนอกการมองเห็น ตาม เอกสารสำหรับนักพัฒนา Apple (2026) onDisappear ไม่รับประกันการเรียกในสถานการณ์ขัดข้องหรือเมื่อแอปถูกยุติโดย watch dog ของระบบ เรียนรู้เพิ่มเติมเกี่ยวกับ SwiftUI ได้ใน บทความเกี่ยวกับ SwiftUI

ประเด็นสำคัญ

  • .onDisappear — ตัวปรับแต่ง SwiftUI สำหรับดำเนินการโค้ดเมื่อ View หายไป
  • ความสมมาตร — onDisappear เป็นคู่ของ onAppear และถูกเรียกในลำดับย้อนกลับ
  • การล้างทรัพยากร — สถานการณ์หลัก: ยกเลิกตัวจับเวลา ปิดการเชื่อมต่อ บันทึกสถานะ
  • การวิเคราะห์ — ผ่าน onDisappear จะส่งเหตุการณ์ปิดหน้าจอ เวลาค้างอยู่ และสิ้นสุดเซสชัน
  • ไม่มีการรับประกัน — onDisappear จะไม่ถูกเรียกเมื่อแอปขัดข้อง

.onDisappear คืออะไร?

.onDisappear คือตัวปรับแต่ง View ใน SwiftUI ที่รับ closure แบบ Void และดำเนินการเมื่อ View ถูกลบออกจากลำดับชั้น เมื่อรวมกับ .onAppear จะสร้างวงจรชีวิตที่สมบูรณ์ของหน้าจอ: การปรากฏ — การทำงาน — การหายไป Apple เปิดตัว onDisappear พร้อมกับ SwiftUI ใน iOS 13 ในฐานะอะนาล็อกของ viewDidDisappear จาก UIKit

ในทางไวยากรณ์ .onDisappear เหมือนกับ onAppear: มันปรับแต่ง View ใด ๆ และแนบ closure ที่ SwiftUI เรนเดอร์เรอร์เรียกเมื่อ view ถูกลบ แตกต่างจาก UIKit ที่ viewDidDisappear จะทำงานหลังจากแอนิเมชันการเปลี่ยนผ่านเสร็จสมบูรณ์เท่านั้น onDisappear ใน SwiftUI สามารถถูกเรียกก่อนที่แอนิเมชันจะสิ้นสุด — ในขณะที่ View ถูกทำเครื่องหมายให้ลบ

ไวยากรณ์ของ onDisappear

ไวยากรณ์พื้นฐาน ของ onDisappear นั้นกระชับเท่ากับ onAppear ตัวปรับแต่งไม่รับพารามิเตอร์เพิ่มเติม — เพียงแค่ closure ซึ่งดำเนินการแบบซิงโครนัสบนเธรดหลัก

swift
struct DetailView: View {
    var body: some View {
        Text("Detail Screen")
            .onDisappear {
                print("DetailView หายไปจากหน้าจอ")
            }
    }
}

.onDisappear ทำงานอย่างไร

กลไกการเรียก ของ onDisappear ตรงกันข้ามกับ onAppear: องค์ประกอบลูกได้รับ onDisappear ก่อน จากนั้นจึงเป็นพ่อแม่ กฎ child-first นี้รับประกันว่าทรัพยากรลูกจะถูกปลดปล่อยก่อนที่ทรัพยากรพ่อแม่จะถูกปลดปล่อย หากองค์ประกอบลูกขึ้นอยู่กับข้อมูลของพ่อแม่ จะต้องสามารถยุติได้อย่างถูกต้องโดยไม่มีบริบทของพ่อแม่

SwiftUI เรียก onDisappear เมื่อ View ถูกลบออกจากกราฟการเรนเดอร์ ทริกเกอร์ได้แก่: pop จาก NavigationStack, การเปลี่ยน TabView, การปิดโมดอล (sheet/fullScreenCover), หรือ View ที่เรนเดอร์แบบมีเงื่อนไข (if/switch) ใน List และ ScrollView onDisappear จะถูกเรียกเมื่อเซลล์เลื่อนออกนอกบัฟเฟอร์โหลดล่วงหน้า

ลำดับการเรียก child-first

ลำดับ child-first หมายความว่าหาก VStack มีสาม View ลูก 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("Child \(id)")
            .onDisappear {
                print("Child \(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 จะถูกเรียกเมื่อปิดโดยโปรแกรม (ผ่าน @Environment(\.dismiss)) หรือท่าทางปัดลง รายละเอียดสำคัญ: หากเปิด sheet ไว้แต่ผู้ใช้เปลี่ยนแอป onDisappear จะไม่ถูกเรียกจนกว่าจะปิดจริง

สถานการณ์onDisappear ถูกเรียกหมายเหตุ
Pop ใน NavigationStackใช่ทันทีหลังจากแอนิเมชัน
เปลี่ยนแท็บ TabViewใช่แท็บปัจจุบัน
ปิด Sheetใช่ก่อนแอนิเมชันเสร็จสมบูรณ์
เลื่อนใน Listใช่เซลล์ออกจากโซนโหลดล่วงหน้า
ย่อแอปไม่ไม่รับประกันการเรียก
ขัดข้อง/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("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)
                    ])
                }
            }
    }
}

.onDisappear กับ .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 publishers onDisappear จะยกเลิกการสมัครสมาชิกผ่าน cancellable?.cancel() ซึ่งป้องกันการอัปเดต UI หลังจากออกจากหน้าจอ ซึ่งสำคัญอย่างยิ่งสำหรับรายการที่มีการแบ่งหน้าและคำค้นหา

สถานการณ์ที่ 3: ปิด WebSocket. ในแอปที่มีการเชื่อมต่อแบบเรียลไทม์ ( messengers, ฟีดราคา) onDisappear จะปิดการเชื่อมต่อ WebSocket เพื่อประหยัดแบตเตอรี่และข้อมูล การเชื่อมต่อใหม่เกิดขึ้นใน onAppear เมื่อกลับมาที่หน้าจอ

การปิด WebSocket ใน onDisappear

WebSocket เป็นทรัพยากรทั่วไปที่ต้องปิดเมื่อออกจากหน้าจอ ในตัวอย่างด้านล่าง onDisappear ตัดการเชื่อมต่อซ็อกเก็ตและ 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 สิ่งนี้อาจทำให้เกิดวงจรตัดการเชื่อมต่อ-เชื่อมต่อใหม่ที่สร้างภาระโดยไม่จำเป็น วิธีแก้คือใช้การหน่วงเวลาหรือตรวจสอบว่าจำเป็นต้องใช้ซ็อกเก็ตบนหน้าจอถัดไปหรือไม่

คำถามที่พบบ่อย

.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 ใหม่ใน body ของพ่อแม่หรือไม่

.onDisappear ทำงานใน SwiftUI บน macOS หรือไม่?

ใช่ .onDisappear รองรับอย่างสมบูรณ์บน macOS (10.15+) ด้วยพฤติกรรมเดียวกัน: ถูกเรียกเมื่อปิดหน้าต่าง ลบแผง split view หรือปิดโมดอล บน macOS onDisappear ยังถูกเรียกเมื่อซ่อนหน้าต่าง (ไม่ใช่แค่เมื่อปิด) ซึ่งสำคัญที่ต้องพิจารณาสำหรับแอป macOS

จะยกเลิก URLSessionTask ใน .onDisappear ได้อย่างไร?

เก็บการอ้างอิงถึง URLSessionTask ใน @State และเรียก task.cancel() ใน onDisappear อีกทางเลือกหนึ่ง ใช้ตัวปรับแต่ง .task ซึ่งยกเลิกการดำเนินการ async โดยอัตโนมัติเมื่อ View หายไป .task เป็นที่นิยมสำหรับการดำเนินการ async ทั้งหมด รวมถึง URLSession

สรุป

  • .onDisappear — ตัวปรับแต่งคู่ของ onAppear สำหรับล้างทรัพยากรและติดตามเมื่อ View หายไป
  • ลำดับ child-first — View ลูกได้รับ onDisappear ก่อนพ่อแม่เพื่อห่วงโซ่การล้างที่ถูกต้อง
  • ไม่รับประกันการเรียก — เมื่อขัดข้อง ย่อ หรือระบบยุติ onDisappear อาจไม่ทำงาน
  • กรณีการใช้งานหลัก — ยกเลิกตัวจับเวลา ปิด WebSocket บันทึกสถานะ ติดตามระยะเวลา
  • การวิเคราะห์ — onDisappear ส่งเหตุการณ์ screen_close พร้อมเวลาค้างอยู่ที่คำนวณผ่าน Date().timeIntervalSince
  • สำหรับการดำเนินการ async — ใช้ .task แทน onDisappear กับ Task {} เนื่องจาก .task ยกเลิกคำขอโดยอัตโนมัติ

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม