9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RxSwiftのDisposeBagは何をしてくれているのか

Last updated at Posted at 2021-05-31

はじめに

RxSwiftを利用したコード内で以下の定義がされていることがよくある。

/// RXのゴミ箱
let disposeBag = DisposeBag()

/*
* 省略
*/

func bind() {
   hogehoge.subscribe(onNext: { [weak self] value in
     // 何らかの処理
   }).disposed(by: disposeBag)
}

このコードはおまじないのように書かれており、コメントにはRxのゴミ箱と記述されていたりすることがあってRx初心者にとっては意味がわからなかった。

そしてsubscribeしているところでメソッドチェーンで.disposed(by: disposeBag)という定義がされており、ゴミ箱に捨てられてるな??みたいな感じになってフワフワしたままだったので、今一度見直すことにした。

DisposeBag

役割

適当なObservableをsubscribeしたとき、戻り値はDisposableオブジェクトなので、dispose()を呼び出せば講読解除できる。

講読解除をしないとメモリリークの原因となるので、解除はしておきたい。
しかしdispose()は自分の好きなタイミングで呼ぶことができるので、一つのクラスで大量のObservableを監視していた場合、都度disposeしてあげなければいけないし、ヒューマンエラー等で抜け漏れる可能性がある。

そこで使用するのがDisposeBagである。
公式のコード上のコメントには下記のように記されている。

Thread safe bag that disposes added disposables on `deinit`.

要するに、deinit時に自動的にDisposeBagに格納されているDisposableオブジェクトを解放してくれるようだ。

書き方

let disposeBag = DisposeBag() //(1)

//(2-1)
hogehoge.subscribe(onNext: { [weak self] value in
    // 何らかの処理
}).disposed(by: disposeBag)

// or

//(2-2)
let disposable = hogehoge.subscribe(onNext: { [weak self] value in
    // 何らかの処理
})

/*
* 任意の場所↓↓↓
*/
disposable.disposed(by: disposeBag) 

(1)で定義をする。DisposeBagはDisposableオブジェクトを格納してくれるので一つだけ定義すれば良い。
これがゴミ箱の定義。

(2-1),(2-2)はやっていることは変わらない。
メソッドチェーンを使ってdisposed(by: disposeBag)を繋げて記述しても良いし、一度プロパティとしてから別途任意な場所で記述するのもOK。

個人的には、コードが散らばらずsubscribeしている箇所を見ればまとまっており、どこでdisposedしているかを探す必要がなくなるメソッドチェーンを使った(2-1)が推し。

講読解除(dispose)されるタイミング

  • 講読対象(Observable)を監視しているとき、onCompletedもしくはonErrorが発生してイベントが終了したら
  • (DisposeBagに監視対象を渡している前提で、) その監視をしているクラスが解放されたら

後者のクラスが解放される時というのは以下のような流れのイメージである。

  1. 画面AからBに遷移する(Bのインスタンスが作成される
  2. Bで何かしらの値を監視する(Bのファイル内でsubscribeが行われる
  3. 画面Bを閉じる(ARCにより参照カウントが0になることでBのインスタンスが解放される

3のタイミングのBのインスタンス解放時にDisposaBagに格納されているオブジェクトが解放される。

終わりに

普段何気なく使っていたDisposeBagですが、監視しているオブジェクトをまとめて解放してくれてメモリリークの原因となることを回避してくれているということがわかりました。

もし、ここが違うよとかがあればご教授頂ければ幸いです。

参照

  1. RxSwift/DisposeBag.swift at main · ReactiveX/RxSwift · GitHub
  2. dispose()とdisposed(by: DisposeBag)を使いこなす - 野生のプログラマZ
  3. RxSwiftの動作を深く理解する - Qiita
9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?