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(自动引用计数)机制,确保资源在合适的时机释放,避免内存泄漏和悬空指针问题。开发者应将其作为视图控制器或模块的标准属性,合理使用以提升代码的健壮性和可维护性。