DisposeBag 是 RxSwift 中用于管理资源释放的核心类之一,它的主要作用是 自动清理订阅的资源 ,防止内存泄漏或悬空指针问题。它是 RxSwift 实现 响应式编程中的资源生命周期管理 的关键工具。
🧠 核心功能
-
自动释放订阅资源
当
DisposeBag被释放(如视图控制器被销毁)时,它会自动调用所有已注册的Disposable对象的dispose()方法,释放资源(如网络请求、观察者等)。 -
线程安全
通过内部的
SpinLock(自旋锁)确保多线程环境下对disposables数组的安全访问。 -
简化资源管理
开发者只需将
Disposable添加到DisposeBag,无需手动调用dispose(),避免手动管理资源的复杂性。
🧩 源码解析
1. 基本结构
swift
public final class DisposeBag: DisposeBase {
private var lock = SpinLock()
private var disposables = [Disposable]()
private var isDisposed = false
deinit {
self.dispose() // 析构时自动释放所有资源
}
}
disposables:存储所有待释放的Disposable对象。isDisposed:标记是否已释放。deinit:当DisposeBag被销毁时,自动调用dispose()释放所有资源。
2. 添加资源
swift
public func insert(_ disposable: Disposable) {
self._insert(disposable)?.dispose()
}
private func _insert(_ disposable: Disposable) -> Disposable? {
self.lock.performLocked {
if self.isDisposed {
return disposable // 已释放,则直接调用 dispose()
}
self.disposables.append(disposable)
return nil
}
}
- 如果
DisposeBag尚未释放,将Disposable添加到disposables。 - 如果
DisposeBag已释放,则直接调用disposable.dispose()。
3. 释放资源
swift
private func dispose() {
let oldDisposables = self._dispose()
for disposable in oldDisposables {
disposable.dispose()
}
}
- 遍历所有
disposables,逐个调用dispose()释放资源。
4. 便捷初始化
swift
public convenience init(disposing disposables: [Disposable]) {
self.init()
self.disposables += disposables
}
- 允许一次性添加多个
Disposable到DisposeBag。
📌 使用场景
✅ 典型用法
swift
let disposeBag = DisposeBag()
// 网络请求订阅
networkService.getData()
.subscribe(onNext: { data in
print("Received data: $data)")
})
.disposed(by: disposeBag)
// UI 事件订阅
button.rx.tap
.subscribe(onNext: {
print("Button tapped")
})
.disposed(by: disposeBag)
disposed(by:):将Disposable添加到DisposeBag,由其自动管理生命周期。DisposeBag通常作为UIViewController或ViewModel的属性,在其生命周期结束时自动释放所有资源。
⚠️ 注意事项
-
避免手动调用
dispose()手动调用
dispose()通常不推荐,因为DisposeBag已经通过deinit自动清理资源。除非你需要提前释放资源(如复杂逻辑),否则应依赖DisposeBag。 -
避免
DisposeBag滥用- 不要创建过多
DisposeBag实例,通常一个UIViewController或ViewModel使用一个DisposeBag即可。 - 如果需要动态管理资源(如切换页面时立即释放),可以使用
CompositeDisposable替代。
- 不要创建过多
-
线程安全
DisposeBag内部通过SpinLock确保线程安全,开发者无需额外处理并发问题。
🔄 与 CompositeDisposable 的区别
| 特性 | DisposeBag |
CompositeDisposable |
|---|---|---|
| 自动释放 | ✅ 在 deinit 时自动释放 |
❌ 需手动调用 dispose() |
| 用途 | 适合生命周期管理(如 UIViewController) |
适合动态管理资源(如切换页面、模块) |
| 线程安全 | ✅ | ✅ |
| 是否可重用 | ❌ 一旦释放不可复用 | ✅ 可多次添加/移除资源 |
📚 实际开发中的价值
-
避免内存泄漏
例如:网络请求或 UI 事件订阅未及时释放,可能导致视图控制器无法被回收。
-
简化代码
不需要手动管理
Disposable的释放,代码更简洁。 -
生命周期绑定
将
DisposeBag作为UIViewController的属性,确保资源在视图控制器销毁时自动释放。
🧪 示例代码
swift
class RxSwiftBaseUseController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
// 网络请求
APIService.shared.fetchData()
.subscribe(onNext: { data in
print("Data fetched: $data)")
})
.disposed(by: disposeBag)
// 按钮点击事件
button.rx.tap
.subscribe(onNext: {
print("Button tapped")
})
.disposed(by: disposeBag)
}
}
- 当
RxSwiftBaseUseController被销毁时,disposeBag会自动释放所有订阅的资源。
🧩 总结
DisposeBag 是 RxSwift 中资源管理的核心工具,通过 自动释放订阅资源,简化了响应式编程中的生命周期管理。它结合 Swift 的 ARC(自动引用计数)机制,确保资源在合适的时机释放,避免内存泄漏和悬空指针问题。开发者应将其作为视图控制器或模块的标准属性,合理使用以提升代码的健壮性和可维护性。