0Pricing
Swift Academy · บทเรียน

การนำตัวสังเกตออกอย่างปลอดภัย

หลีกเลี่ยงหน่วยความจำรั่วและการหยุดทำงานจากตัวสังเกตที่หมดอายุ

การนำตัวสังเกตออกอย่างปลอดภัย เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

การลบตัวเฝ้าดูอย่างปลอดภัย

ต้องลบตัวเฝ้าดูเมื่อไม่จำเป็นต้องใช้งานอีกต่อไป ตัวเฝ้าดูที่ยังค้างอยู่อาจทำงานหลังจาก Owner ถูกทำลายแล้ว ทำให้เกิดข้อผิดพลาด หรืออาจทำให้โปรแกรมหยุดทำงานใน API รุ่นเก่า

เหตุใดการลบจึงสำคัญ

ในอดีต ตัวเฝ้าดูแบบซีเลกเตอร์ต้องถูกลบใน deinit เพื่อหลีกเลี่ยงการส่งข้อความไปยังอ็อบเจกต์ที่ถูกคืนหน่วยความจำแล้ว

import Foundation

class Watcher: NSObject {
    override init() { super.init() }
    deinit { NotificationCenter.default.removeObserver(self) }
}
print("Removes itself on deinit")

removeObserver(self)

การเรียก removeObserver(self) จะยกเลิกการเฝ้าดูทั้งหมดที่อ็อบเจกต์นั้นสร้างไว้ภายในการเรียกครั้งเดียว

import Foundation

class VM: NSObject {
    func stop() { NotificationCenter.default.removeObserver(self) }
}
VM().stop()
print("Removed all observations for self")

การลบชื่อเฉพาะรายการ

คุณสามารถลบการเฝ้าดูเพียงรายการเดียวได้โดยส่งชื่อและอ็อบเจกต์เข้าไป โดยการเฝ้าดูรายการอื่นจะยังคงอยู่

import Foundation

let center = NotificationCenter.default
let obj = NSObject()
let name = Notification.Name("ping")
center.removeObserver(obj, name: name, object: nil)
print("Removed a specific observation")

ตัวเฝ้าดูแบบใช้ token

addObserver แบบใช้โคลเชอร์จะส่งคืน token ที่ไม่เปิดเผยรายละเอียด เก็บ token นี้ไว้ แล้วลบตัวเฝ้าดูด้วย token ดังกล่าว

import Foundation

let center = NotificationCenter.default
let name = Notification.Name("ping")
let token = center.addObserver(forName: name, object: nil, queue: nil) { _ in }
center.removeObserver(token)
print("Removed via token")

การจัดเก็บ token

เก็บ token ไว้ในพร็อพเพอร์ตี เพื่อให้ token มีอายุการใช้งานนานเท่าที่ต้องการเฝ้าดู และลบออกเมื่อเสร็จสิ้น

import Foundation

class Model {
    var token: NSObjectProtocol?
    func start() {
        token = NotificationCenter.default.addObserver(
            forName: Notification.Name("x"), object: nil, queue: nil) { _ in }
    }
    func stop() {
        if let t = token { NotificationCenter.default.removeObserver(t) }
    }
}
let m = Model(); m.start(); m.stop()
print("Lifecycle managed")

การล้างข้อมูลอัตโนมัติด้วย deinit

ลบ token ใน deinit เพื่อให้การเฝ้าดูสิ้นสุดลงเมื่อ Owner ถูกคืนหน่วยความจำ

import Foundation

class Owner {
    var token: NSObjectProtocol?
    deinit { if let t = token { NotificationCenter.default.removeObserver(t) } }
}
print("Token removed on deinit")

หมายเหตุเกี่ยวกับอายุการใช้งานสมัยใหม่

ในรันไทม์รุ่นใหม่ ตัวเฝ้าดูที่เพิ่มด้วย API แบบบล็อกจะถูกลบโดยอัตโนมัติเมื่อ token ถูกคืนหน่วยความจำ แต่การลบอย่างชัดเจนยังคงเป็นทางเลือกที่ปลอดภัยและเข้าใจได้ง่าย

import Foundation

// Holding the token in a property controls its lifetime.
class C { var token: NSObjectProtocol? }
print("Token lifetime equals observation lifetime")

การหลีกเลี่ยงวงจรการยึดครอง

หากตัวเฝ้าดูแบบโคลเชอร์จับ self ไว้อย่างแน่นหนา ให้ใช้ [weak self] เพื่อหลีกเลี่ยงวงจรการยึดครองที่ทำให้ไม่สามารถคืนหน่วยความจำได้

import Foundation

class VM {
    var token: NSObjectProtocol?
    func start() {
        token = NotificationCenter.default.addObserver(
            forName: Notification.Name("x"), object: nil, queue: nil) { [weak self] _ in
            self?.handle()
        }
    }
    func handle() { print("handled") }
}
VM().start()

การลบซ้ำปลอดภัย

การลบตัวเฝ้าดูที่ถูกลบไปแล้วไม่มีผลเสีย ดังนั้นการล้างข้อมูลเชิงป้องกันจะไม่ทำให้โปรแกรมหยุดทำงาน

import Foundation

let center = NotificationCenter.default
let obj = NSObject()
center.removeObserver(obj)
center.removeObserver(obj) // no harm
print("Safe to remove twice")

สรุปแนวทางปฏิบัติที่ดี

ควรเลือกใช้โคลเชอร์แบบใช้ token เก็บ token ไว้ ลบใน deinit และจับ self แบบ weak วิธีนี้ช่วยให้อายุการใช้งานของการเฝ้าดูถูกต้อง

import Foundation

class Best {
    var token: NSObjectProtocol?
    deinit { token.map { NotificationCenter.default.removeObserver($0) } }
}
print("Followed best practices")

ตรวจสอบความเข้าใจ

คุณจะลบตัวเฝ้าดูแบบโคลเชอร์ที่เพิ่มด้วย addObserver(forName:...) ได้อย่างไร

ทบทวน

ลบตัวเฝ้าดูที่ไม่จำเป็นต้องใช้งานอีกต่อไปเสมอ ใช้ removeObserver(self) สำหรับตัวเฝ้าดูแบบซีเลกเตอร์ และใช้ token ที่ส่งคืนมาสำหรับตัวเฝ้าดูแบบโคลเชอร์ เก็บ token ไว้ ล้างข้อมูลใน deinit และจับ self แบบ weak ต่อไปคือการเปรียบเทียบรูปแบบตัวเฝ้าดูกับทางเลือกอื่น

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

บทเรียน “การนำตัวสังเกตออกอย่างปลอดภัย” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การนำตัวสังเกตออกอย่างปลอดภัย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การนำตัวสังเกตออกอย่างปลอดภัย”

หลีกเลี่ยงหน่วยความจำรั่วและการหยุดทำงานจากตัวสังเกตที่หมดอายุ คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การนำตัวสังเกตออกอย่างปลอดภัย” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม

ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การโพสต์และสังเกตการแจ้งเตือน
  2. ข้อมูลส่วนเพิ่มเติม userInfo ของการแจ้งเตือน
  3. การนำตัวสังเกตออกอย่างปลอดภัย
  4. ทางเลือกแทนรูปแบบตัวสังเกต
← กลับไปที่ Swift Academy