安全移除观察者
避免过期观察者导致内存泄漏和崩溃。
安全移除观察者 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。
安全地移除观察者
不再需要观察者时必须将其移除。悬空的观察者可能会在其所有者消失后仍然触发,从而导致错误;在旧接口中甚至可能导致崩溃。
为什么移除很重要
基于选择器的观察者过去必须在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 移除观察者。
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 存储在属性中,使它在您需要观察期间一直存在,并在完成后将其移除。
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,使所有者释放后观察也随之结束。
import Foundation
class Owner {
var token: NSObjectProtocol?
deinit { if let t = token { NotificationCenter.default.removeObserver(t) } }
}
print("Token removed on deinit")现代生命周期提示
在较新的运行时中,使用代码块接口添加的观察者会在 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。这样可以确保观察的生命周期正确。
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。下一步:了解观察者模式与其他方案的比较。
常见问题解答
「安全移除观察者」课时是免费的吗?
是的 — 「安全移除观察者」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。
「安全移除观察者」这节课中我会学到什么?
避免过期观察者导致内存泄漏和崩溃。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Swift Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「安全移除观察者」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Swift Academy 课中编写并运行代码吗?
能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。