การนำตัวสังเกตออกอย่างปลอดภัย
หลีกเลี่ยงหน่วยความจำรั่วและการหยุดทำงานจากตัวสังเกตที่หมดอายุ
การนำตัวสังเกตออกอย่างปลอดภัย เป็นบทเรียน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การโพสต์และสังเกตการแจ้งเตือน
- ข้อมูลส่วนเพิ่มเติม userInfo ของการแจ้งเตือน
- การนำตัวสังเกตออกอย่างปลอดภัย
- ทางเลือกแทนรูปแบบตัวสังเกต