前言
如果看过RxSwift的文档,一定看过官方这样一个例子。
传统实现方法:
var token: NSObjectProtocol!
override func viewDidLoad() {
super.viewDidLoad()
token = NotificationCenter.default.addObserver(
forName: UIApplication.didBecomeActiveNotification,
object: nil, queue: nil) { (notification) in
print("Application Will Enter Foreground")
}
}
deinit {
NotificationCenter.default.removeObserver(token)
}
通过 Rx 来实现:
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.rx
.notification(UIApplication.didBecomeActiveNotification)
.subscribe(onNext: { (notification) in
print("Application Will Enter Foreground")
})
.disposed(by: disposeBag)
}
为何在Rx框架下,NotificationCenter无需管理观察者的生命周期?
让我们一步一步往下看。
RxCocoa/NotificationCenter+Rx.swift源码解析
好的,下面解析一下 NotificationCenter.default.rx.notification
的内部代码实现原理(以 RxSwift 6.x 为例):
1. 扩展入口
RxSwift 通过对 NotificationCenter
的扩展,增加了 rx
属性:
// RxCocoa/NotificationCenter+Rx.swift
extension Reactive where Base: NotificationCenter {
public func notification(_ name: Notification.Name, object: AnyObject? = nil) -> Observable<Notification> {
return Observable.create { observer in
let token = self.base.addObserver(forName: name, object: object, queue: nil) { notification in
observer.onNext(notification)
}
return Disposables.create {
self.base.removeObserver(token)
}
}
}
}
2. 实现细节
Observable.create
创建一个 Observable。- 当有订阅者时,调用
addObserver(forName:object:queue:using:)
注册通知观察者。 - 每当收到通知时,调用
observer.onNext(notification)
,把通知事件推送给订阅者。 - 返回一个
Disposable
,当订阅释放时(比如disposeBag
释放),会自动调用removeObserver(token)
移除观察者。
3. 生命周期管理
- 只要订阅还在,观察者就存在。
- 当订阅释放,
Disposable
的清理逻辑会移除观察者,避免内存泄漏。
4. 小结
NotificationCenter.default.rx.notification
本质上是用 RxSwift 的 Observable 包装了系统的通知注册和移除逻辑,自动管理观察者的生命周期,简化了通知的使用。Observable.create
函数入参是传入一个闭包:@escaping (AnyObserver<Element>) -> Disposable
,注意此闭包需要返回Disposable
Disposables.create
的入参也是传入一个闭包create(with dispose: @escaping () -> Void)
代码整体书写与理解并不好懂,简单来说,就是通过分类进行了观察者的移除,所以我们在调用的时候无需再调用removeObserver
方法了。
那么Rx里面的removeObserver
又是何时被调用的呢?我们接着继续。
RxSwift/AnonymousDisposable.swift源码解析
这个类有点长,我就只贴部分关键代码进行解析:
extension Disposables {
public static func create(with dispose: @escaping () -> Void) -> Cancelable {
AnonymousDisposable(disposeAction: dispose)
}
}
这段代码就是我们用的非常多的Disposables.create
的具体方法,它会去构建一个AnonymousDisposable
类,入参就是一个disposeAction(处理动作)。
在NotificationCenter+Rx.swif中,传入的disposeAction就是self.base.removeObserver(token)
然后我们看看AnonymousDisposable
中的关键代码:
private final class AnonymousDisposable : DisposeBase, Cancelable {
public typealias DisposeAction = () -> Void
private let disposed = AtomicInt(0)
private var disposeAction: DisposeAction?
fileprivate init(disposeAction: @escaping DisposeAction) {
self.disposeAction = disposeAction
super.init()
}
fileprivate func dispose() {
if fetchOr(self.disposed, 1) == 0 {
if let action = self.disposeAction {
self.disposeAction = nil
action()
}
}
}
}
1. 主要属性
disposeAction
:存储你传入的释放闭包。
2. 构造方法
fileprivate init(disposeAction: @escaping DisposeAction)
- 构造时传入释放闭包,保存到
disposeAction
。
3. dispose 方法
fileprivate func dispose() {
if fetchOr(self.disposed, 1) == 0 {
if let action = self.disposeAction {
self.disposeAction = nil
action()
}
}
}
- 通过原子操作保证只执行一次释放逻辑。
- 如果action存在,则执行
disposeAction
,并将其置为 nil,防止重复调用或者释放。
4. 小结
- AnonymousDisposable 用于包装一个自定义的释放动作,保证释放动作只会被执行一次且线程安全。
- 你通常通过
Disposables.create(with:)
来创建它。 - 这是 RxSwift 资源释放和订阅管理的基础设施之一。
好了,到这里,我们就顺藤摸瓜找到了传入的self.base.removeObserver(token)被保存到了哪里,并且知道了在AnonymousDisposable
中通过调用dispose()
方法进行了执行,那么这个dispose()
又是何时被执行的呢?
我们离真相越来越近了。
RxSwift/DisposeBag.swift源码解析
我贴出了DisposeBag
的关键代码:
public final class DisposeBag: DisposeBase {
private var disposables = [Disposable]()
public override init() {
super.init()
}
public func insert(_ disposable: Disposable) {
self._insert(disposable)?.dispose()
}
private func dispose() {
let oldDisposables = self._dispose()
for disposable in oldDisposables {
disposable.dispose()
}
}
deinit {
self.dispose()
}
}
DisposeBag
对象析构函数被调用的时候,会调用它自己的dispose()
方法dispose()
方法内部,会将disposables
数组的中每个Disposable
元素进行遍历,并调用Disposable
对象的dispose()
方法。
到此,我们可以看出最开始的self.base.removeObserver(token)这个移除观察者的方法会在DisposeBag
对象的析构函数中调用。
即可以认为self.base.removeObserver(token)是在DisposeBag
的生命周期中的销毁阶段完成了移除!
如果上面的代码觉得看的不够清晰,我们来一段拆分的代码。
一个NotificationCenter.default.rx 的生成序列、被订阅、最后订阅被销毁的完整流程
1. Observable 生成
你可以通过多种方式创建 Observable,例如:
let observable = NotificationCenter.default.rx.notification(UIApplication.didBecomeActiveNotification)
2. 被订阅
let disposable = observable.subscribe(onNext: { notification in
print("App became active")
})
流程:
subscribe
会触发 Observable 的事件推送逻辑。- 你传入的闭包会被包装成一个观察者(Observer)。
- Observable 会把事件(如 onNext、onCompleted)推送给 Observer。
subscribe
返回一个Disposable
,用于后续取消订阅。
3. 订阅被销毁
使用 DisposeBag
let disposeBag = DisposeBag()
let disposable = observable.subscribe(onNext: { value in
print(value)
})
disposable.disposed(by: disposeBag)
- 当
disposeBag
被释放时(比如控制器销毁),它会自动调用所有持有的Disposable
的dispose()
方法,自动取消订阅。 .disposed(by: disposeBag)
这个方法,只是一个对disposeBag.insert(disposable)简单封装,方便链式调用
extension Disposable {
public func disposed(by bag: DisposeBag) {
bag.insert(self)
}
}
4. 小结
来,让我们将上面的这个周期的代码在一个ViewController中进行一个完整演示
class ViewController: UIViewController {
/// 创建一个与ViewController对象生命周期绑定的disposeBag,ViewController销毁,disposeBag就销毁
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
/// 生成序列
let observable = NotificationCenter.default.rx.notification(UIApplication.didBecomeActiveNotification)
/// 订阅序列,生成一个可以处理的disposable
let disposable = observable.subscribe(onNext: { notification in
print("App became active")
})
/// 将disposable丢入disposeBag中,当ViewController销毁对象销毁时,disposable就会回被销毁,disposable里面封装的removeObserver(token)也会被销毁
disposable.disposed(by: disposeBag)
}
}
总结
本文通过对比传统的 NotificationCenter 观察者管理方式与 RxSwift 的响应式实现,深入剖析了 RxSwift 如何自动管理观察者的生命周期,避免了手动移除观察者的繁琐和潜在的内存泄漏风险。
在 RxSwift 中,NotificationCenter.default.rx.notification
通过 Observable 的机制,将系统通知的注册与移除过程封装起来。当你订阅通知时,RxSwift 自动注册观察者,并返回一个 Disposable;当你将 Disposable 加入到 DisposeBag 后,随着 DisposeBag 的销毁(通常与控制器生命周期绑定),RxSwift 会自动调用 Disposable 的 dispose 方法,最终移除观察者。这一切都通过源码中的闭包传递和资源管理类(如 AnonymousDisposable、DisposeBag)实现,保证了释放动作只会被执行一次且线程安全。
通过源码分析和流程梳理,我们可以清晰地看到 RxSwift 在资源管理上的优雅设计:
- 事件订阅与资源释放解耦,开发者无需关心何时移除观察者;
- 只需将 Disposable 交给 DisposeBag,生命周期管理自动完成;
- 极大提升了代码的安全性和可维护性。
总之,RxSwift 的响应式封装让通知监听变得更简单、更安全、更易维护,是现代 iOS 开发中推荐的最佳实践之一。
你也可以在Swift的原生Combine框架中找到类似的处理方式,这里就不过多赘述。