DisposeBagに複数まとめて登録する時は`.disposed(by:)`を使うよりも`insert()`を使う方が良い
TL;DR
hoge.subscribe(
onNext: { ~ },
onError: { ~ }
)
.disposed(by: disposeBag)
fuga.subscribe(
onNext: { ~ },
onError: { ~ }
)
.disposed(by: disposeBag)
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:)
を見ていきます
extension Disposable {
/// Adds `self` to `bag`
///
/// - parameter bag: `DisposeBag` to add `self` to.
public func disposed(by bag: DisposeBag) {
bag.insert(self)
}
}
はい、bag
にinsert
してるだけですねw
ではこのinsert
を見ていきます
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
をまとめて処理するためのメソッドも用意されています。
/// 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()
、積極的に使っていこう!
2021/01/26追記
RxSwift 6がリリースされ、DisposeBag.insert
がFunction Builderに対応したようです。
disposeBag.insert {
hoge.subscribe(
onNext: { ~ },
onError: { ~ }
)
fuga.subscribe(
onNext: { ~ },
onError: { ~ }
)
}
カンマが不要になるので項目が増える際のdiffも減ってレビューもしやすくなりますね。
参考
https://github.com/ReactiveX/RxSwift/blob/master/RxSwift/Disposables/DisposeBag.swift
https://dev.to/freak4pc/what-s-new-in-rxswift-6-2nog#new-raw-disposebag-endraw-function-builder
Author And Source
この問題について(DisposeBagに複数まとめて登録する時は`.disposed(by:)`を使うよりも`insert()`を使う方が良い), 我々は、より多くの情報をここで見つけました https://qiita.com/417_72ki/items/5943700dbe5d3663512a著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .