RxSwift 中的 DisposeBag解析

DisposeBagRxSwift 中用于管理资源释放的核心类之一,它的主要作用是 自动清理订阅的资源 ,防止内存泄漏或悬空指针问题。它是 RxSwift 实现 响应式编程中的资源生命周期管理 的关键工具。


🧠 核心功能

  1. 自动释放订阅资源

    DisposeBag 被释放(如视图控制器被销毁)时,它会自动调用所有已注册的 Disposable 对象的 dispose() 方法,释放资源(如网络请求、观察者等)。

  2. 线程安全

    通过内部的 SpinLock(自旋锁)确保多线程环境下对 disposables 数组的安全访问。

  3. 简化资源管理

    开发者只需将 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
}
  • 允许一次性添加多个 DisposableDisposeBag

📌 使用场景

典型用法

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 通常作为 UIViewControllerViewModel 的属性,在其生命周期结束时自动释放所有资源。

⚠️ 注意事项

  1. 避免手动调用 dispose()

    手动调用 dispose() 通常不推荐,因为 DisposeBag 已经通过 deinit 自动清理资源。除非你需要提前释放资源(如复杂逻辑),否则应依赖 DisposeBag

  2. 避免 DisposeBag 滥用

    • 不要创建过多 DisposeBag 实例,通常一个 UIViewControllerViewModel 使用一个 DisposeBag 即可。
    • 如果需要动态管理资源(如切换页面时立即释放),可以使用 CompositeDisposable 替代。
  3. 线程安全
    DisposeBag 内部通过 SpinLock 确保线程安全,开发者无需额外处理并发问题。


🔄 CompositeDisposable 的区别

特性 DisposeBag CompositeDisposable
自动释放 ✅ 在 deinit 时自动释放 ❌ 需手动调用 dispose()
用途 适合生命周期管理(如 UIViewController 适合动态管理资源(如切换页面、模块)
线程安全
是否可重用 ❌ 一旦释放不可复用 ✅ 可多次添加/移除资源

📚 实际开发中的价值

  1. 避免内存泄漏

    例如:网络请求或 UI 事件订阅未及时释放,可能导致视图控制器无法被回收。

  2. 简化代码

    不需要手动管理 Disposable 的释放,代码更简洁。

  3. 生命周期绑定

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

相关推荐
麦兜*5 小时前
Swift + Xcode 开发环境搭建终极指南
开发语言·ios·swiftui·xcode·swift·苹果vision pro·swift5.6.3
专注API从业者5 小时前
Python + 淘宝 API 开发:自动化采集商品数据的完整流程
大数据·运维·前端·数据挖掘·自动化
烛阴6 小时前
TypeScript高手密技:解密类型断言、非空断言与 `const` 断言
前端·javascript·typescript
样子20187 小时前
Uniapp 之renderjs解决swiper+多个video卡顿问题
前端·javascript·css·uni-app·html
Nicholas687 小时前
flutterAppBar之SystemUiOverlayStyle源码解析(一)
前端
黑客飓风7 小时前
JavaScript 性能优化实战大纲
前端·javascript·性能优化
emojiwoo8 小时前
【前端基础知识系列六】React 项目基本框架及常见文件夹作用总结(图文版)
前端·react.js·前端框架
张人玉9 小时前
XML 序列化与操作详解笔记
xml·前端·笔记
杨荧9 小时前
基于Python的宠物服务管理系统 Python+Django+Vue.js
大数据·前端·vue.js·爬虫·python·信息可视化
YeeWang10 小时前
🎉 Eficy 让你的 Cherry Studio 直接生成可预览的 React 页面
前端·javascript