Help us understand the problem. What is going on with this article?

DisposeBagに複数まとめて登録する時は`.disposed(by:)`を使うよりも`insert()`を使う方が良い

TL;DR

hoge.subscribe(
    onNext: { ~ },
    onError: { ~ }
)
.disposed(by: disposeBag)
fuga.subscribe(
    onNext: { ~ },
    onError: { ~ }
)
.disposed(by: disposeBag)

disposeBag.insert(
    hoge.subscribe(
        onNext: { ~ },
        onError: { ~ }
    ),
    fuga.subscribe(
        onNext: { ~ },
        onError: { ~ }
    )
)

って書こうぜって話

DisposeBagとは

subscribeしているObservable等をまとめてdisposeしてくれる仕組みです。
DisposeBagオブジェクトが破棄されるタイミングで抱えているDisposableに対してdispose()をかけるようになっています。

参考記事はこちら

DisposeBagの実装

ソース
https://github.com/ReactiveX/RxSwift/blob/master/RxSwift/Disposables/DisposeBag.swift

まずはdisposed(by:)を見ていきます

DisposeBag.swift
extension Disposable {
    /// Adds `self` to `bag`
    ///
    /// - parameter bag: `DisposeBag` to add `self` to.
    public func disposed(by bag: DisposeBag) {
        bag.insert(self)
    }
}

はい、baginsertしてるだけですねw
ではこのinsertを見ていきます

DisposeBag.swift
private var _lock = SpinLock()

// state
private var _disposables = [Disposable]()
private var _isDisposed = false

/// Adds `disposable` to be disposed when dispose bag is being deinited.
///
/// - parameter disposable: Disposable to add.
public func insert(_ disposable: Disposable) {
    self._insert(disposable)?.dispose()
}

private func _insert(_ disposable: Disposable) -> Disposable? {
    self._lock.lock(); defer { self._lock.unlock() }
    if self._isDisposed {
        return disposable
    }
    self._disposables.append(disposable)
    return nil
}

これを見ると、
- bagが既に破棄されている場合にはinsertされたDisposableも破棄しちゃう
- bagが破棄されていないなら内部のキューに積む

といった動きをしていることが分かります。

また、DisposeBagには複数のDisposableをまとめて処理するためのメソッドも用意されています。

DisposeBag.swift
/// Convenience function allows a list of disposables to be gathered for disposal.
public func insert(_ disposables: Disposable...) {
    self.insert(disposables)
}

/// Convenience function allows an array of disposables to be gathered for disposal.
public func insert(_ disposables: [Disposable]) {
    self._lock.lock(); defer { self._lock.unlock() }
    if self._isDisposed {
        disposables.forEach { $0.dispose() }
    } else {
        self._disposables += disposables
    }
}

こちらも

  • bagが既に破棄されている場合にはinsertされたDisposableも破棄しちゃう
  • bagが破棄されていないなら内部のキューに積む

という点では一緒ですね。

つまり、

hoge.subscribe(
    onNext: { ~ },
    onError: { ~ }
)
.disposed(by: disposeBag)
fuga.subscribe(
    onNext: { ~ },
    onError: { ~ }
)
.disposed(by: disposeBag)

といったコードは

disposeBag.insert(
    hoge.subscribe(
        onNext: { ~ },
        onError: { ~ }
    )
)

disposeBag.insert(
    fuga.subscribe(
        onNext: { ~ },
        onError: { ~ }
    )
)

と置き換えられ、更に

disposeBag.insert(
    hoge.subscribe(
        onNext: { ~ },
        onError: { ~ }
    ),
    fuga.subscribe(
        onNext: { ~ },
        onError: { ~ }
    )
)

と置き換えられることが分かります。

見た目的にもここでまとめてdisposeBagに突っ込んでることが分かりやすくなりますし、
SpinLockについては詳しくないので断言はできませんが、
.disposed(by:)だと一々ロックかけたり解除したりを繰り返すのに対し、
まとめてinsertするなら1回のロックで済むのでパフォーマンス的にも良いんじゃないかなーと思ってます。
(あと、.繋ぎは改行するような規約の現場なら、シンプルに行数が減るのでLinterにも優しくなるはず)

結論

DisposeBag.insert()、積極的に使っていこう!

参考

https://github.com/ReactiveX/RxSwift/blob/master/RxSwift/Disposables/DisposeBag.swift

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away