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

相关推荐
翻滚吧键盘7 分钟前
vue绑定一个返回对象的计算属性
前端·javascript·vue.js
秃了也弱了。25 分钟前
Chrome谷歌浏览器插件ModHeader,修改请求头,开发神器
前端·chrome
恋猫de小郭37 分钟前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
乆夨(jiuze)1 小时前
记录H5内嵌到flutter App的一个问题,引发后面使用fastClick,引发后面input输入框单击无效问题。。。
前端·javascript·vue.js
忧郁的蛋~1 小时前
HTML表格导出为Excel文件的实现方案
前端·html·excel
小彭努力中1 小时前
141.在 Vue 3 中使用 OpenLayers Link 交互:把地图中心点 / 缩放级别 / 旋转角度实时写进 URL,并同步解析显示
前端·javascript·vue.js·交互
然我1 小时前
别再只用 base64!HTML5 的 Blob 才是二进制处理的王者,面试常考
前端·面试·html
NanLing1 小时前
【纯前端推理】纯端侧 AI 对象检测:用浏览器就能跑的深度学习模型
前端
呆呆的心2 小时前
前端必学:从盒模型到定位,一篇搞定页面布局核心 🧩
前端·css
小飞悟2 小时前
前端高手才知道的秘密:Blob 居然这么强大!
前端·javascript·html