【RxSwift】DisposeBagクラスの使い方!Disposable

この記事からわかること

  • RxSwift購読廃棄するDisposeとは?
  • DisposeBagクラス使い方
  • Disposableクラスとは?
  • .disposed(by:)メソッド意味

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

RxSwiftの購読を廃棄するDisposeの概要と使い方などをまとめていきます。

おすすめ記事:【RxSwiftとは?導入方法と使い方まとめ!ストリームを理解する

RxSwiftのDisposeとは?

RxSwiftではObservableオブジェクトを購読(観測を開始)することでイベント通知を取得して処理を実装していました。これには観測されるストリームと観測する側(Observer)が必要です。

【RxSwift】DisposeBagクラスの使い方!Disposable

しかし対象のストリームをいつまでも観測し続けているとメモリリークの原因を引き起こす可能性があります。そのためにはどこかのタイミングで観測を停止する必要があります。それを「Dispose(廃棄)」と呼びます。

メモリリークとは?

メモリリークとは確保したメモリ領域を解放し忘れることによりメモリが確保され続けた状態になってしまうプログラムバグの1種です。

メモリは有限であり、使用すればするほど動作が重くなったり予期せぬ挙動を引き起こす原因になります。 Observableオブジェクトを購読開始後、観測が不要になったタイミングで廃棄処理を行うことが適切なメモリ管理を行う上で重要になります。

廃棄方法

観測しているObservableオブジェクトでは明示的に実行しなくてもonErrorまたはonCompletedが呼ばれイベントが終了した際に自動で廃棄処理を行ってくれます。

しかし両者が呼ばれない場合などは廃止処理を実装する必要があります。

実際に廃棄処理を行うのはDisposableの持つdisposeメソッドです。

ですがdisposeメソッドを手動で呼び出すことは公式より推奨されておらずDisposeBagクラスやtakeUntilメソッドなどを使用した方法が推奨されています。

”Note that you usually do not want to manually call dispose; this is only an educational example. Calling dispose manually is usually a bad code smell. There are better ways to dispose of subscriptions such as DisposeBag, the takeUntil operator, or some other mechanism.”

引用:GitHub-ReactiveX/RxSwift/Documentation/GettingStarted.md

まだ自動で廃止処理が行われる場合でも確実にリソースを解放できるように廃止処理は記述しておくことが重要です。

”Using dispose bags or takeUntil operator is a robust way of making sure resources are cleaned up. We recommend using them in production even if the sequences will terminate in finite time.”

引用:GitHub-ReactiveX/RxSwift/Documentation/GettingStarted.md

DisposeBagクラス

公式リファレンス:RxSwift/Disposables/DisposeBag.swift

RxSwiftでは廃棄処理のためのDisposeBagクラスが用意されています。このクラスを使用することで登録した購読処理を一括で廃棄することができます。よく「ゴミ箱」と表現されますがまさしく「溜めて捨てる」という役割を果たしてくれます。

DisposeBagクラスが一括で購読を破棄するタイミングはdeinit(デイニシャライザ)が呼ばれる時です。

実際の使い方

ここではTextFieldの入力イベントを観測しLabelのテキストにバインディングさせる場合を例に実用的な使い方を見てみます。 TextFieldの入力イベントではonNextしか呼ばれないので明示的に廃棄する必要があります。

ステップ1:DisposeBagインスタンスの生成

まずはDisposeBagインスタンスをViewControllerクラスのプロパティとして定義しておきます。ゴミ箱を設置したイメージです。

let disposeBag = DisposeBag()

ステップ2:disposedメソッドで登録

subscribeメソッドの返り値はDisposableオブジェクトなのでここからdisposedメソッドを呼び出します。このメソッドの引数にDisposeBagオブジェクトを渡すことでゴミ箱との紐付けが完了します。

text.subscribe(onNext: { [weak self] text in
                label.text = text
            }).disposed(by: disposeBag)

ステップ3:DisposeBagの実行タイミング

DisposeBagの実行タイミングはデイニシャライザが呼ばれた時なのでViewControllerクラスが解放されたタイミング(画面遷移など)に実行されます。

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {

    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let label = UILabel()
        label.frame = CGRect(x:130, y:200,width:200, height:50)
        label.text = "placeholder..." // textField.text とBindingされるので表示されることはない
        self.view.addSubview(label)

        let textField = UITextField()
        textField.frame = CGRect(x:130, y:300,width:200, height:50)
        textField.borderStyle = UITextField.BorderStyle.line
        self.view.addSubview(textField)

        let text = textField.rx.text.asObservable() // Observableクラスの取得
        text.subscribe(onNext: { [weak self] text in
                label.text = text // 変化した値をUIとリンク
            }).disposed(by: disposeBag)
    }
}

参考文献:ReactiveX/RxSwift/Documentation/GettingStarted.md

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index