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

相关推荐
酒鼎6 分钟前
学习笔记(12-02)事件循环 - 实战案例 —⭐
前端·javascript
Bigger11 分钟前
第一章:我是如何剖析 Claude Code 整体架构与启动流程的
前端·aigc·claude
竹林81817 分钟前
从“连接失败”到丝滑登录:我用 ethers.js v6 搞定 MetaMask 钱包连接的全过程
前端·javascript
oi..21 分钟前
《Web 安全入门|XSS 漏洞原理、CSP 策略与 HttpOnly 防护实践》
前端·网络·测试工具·安全·web安全·xss
UXbot30 分钟前
2026年AI全链路产品开发工具对比:5款从创意到上线一站式平台深度解析
前端·ui·kotlin·软件构建·swift·原型模式
Digitally32 分钟前
如何将 iPad 上的照片传输到 U 盘(4 种解决方案)
ios·ipad
一拳不是超人40 分钟前
前端工程师也要懂的服务器部署知识:从 Nginx 到 CI/CD
服务器·前端
AlkaidSTART1 小时前
TanStack Query 技术指南:异步状态管理核心实践
前端·react.js
种花家的强总1 小时前
前端项目开发/维护中降低成本的方式之一:降低耦合度
前端
Palpitate_LL1 小时前
从XSS到“RCE“的PC端利用链构建
前端·xss