0Pricing
Swift Academy · 课时

安全移除观察者

避免过期观察者导致内存泄漏和崩溃。

安全移除观察者 是 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 发布和观察通知
  2. 通知的 userInfo 载荷
  3. 安全移除观察者
  4. 观察者模式的替代方案
← 返回 Swift Academy