66
54

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 5 years have passed since last update.

RxSwiftのDisposeBagとWeakの関係について

Posted at

はじめに

以下のコードを見たときに違和感を覚えたので、検証した結果を書きます。
違和感を覚えたのは以下のコードです。

class UserViewController: UIViewController {
    let disposeBag = DisposeBag()

    private func loadUser(user:User){ 
        API.User.Get(user.id).subscribeNext { user in
            self.userNameLabel.text = user.name
        }.addDisposableTo(disposeBag)
    }
}

何が起こるのか?

DisposeBagObservableを自動的に解放するための便利な機能です。
はじめてのRxSwiftのメモに書いてますので、見てください。

「このDisposeBagによってselfが解放されるはず。」

という意図で書かれたコードだと思いますが、実際は意図とは違う潜在バグを引き起こすコードでした。
このコードは正常に動きますが、deinitが呼ばれません。
すなわち、UserViewControllerが解放されません。

そのうちメモリリークが発生しますが、開発環境では気づきにくいでしょう。

何が起こっているのか?

問題は以下のコードにあります。

API.User.Get(user.id).subscribeNext { user in
    self.userNameLabel.text = user.name
}.addDisposableTo(disposeBag)

このコードの中でselfを参照しているため、selfが解放されません。
selfが解放されないとdisposeBagも解放されないため、結果的に相互参照が発生してしまいます。

解決策

解決策は簡単で以下のようにselfを弱参照すれば良いだけです。

class UserViewController: UIViewController {
    let disposeBag = DisposeBag()

    private func loadUser(user:User){ 
        API.User.Get(user.id).subscribeNext { [weak self] user in
            self?.userNameLabel.text = user.name
        }.addDisposableTo(disposeBag)
    }
}

このようにする事でselfが解放されるためdisposeBagも同時に解放されObservableも解放されます。
API.User.Getの中でonCompletedなどが呼び出されていれば、addDisposableTo(disposeBag)は不要です。)

最後に

基本的な事ですが、新しい概念(ここで言うとDisposeBag)が入ると混乱して基本的な事が抜けてしまう事があります。
僕もコードを見たときに感じたのは違和感だけで、確証は得られなかったので検証は大切だと思いました。

未検証のもの

上記のコードは以下のように書いても解放されると思います。

class UserViewController: UIViewController {
    let disposeBag = DisposeBag()

    private func loadUser(user:User){ 
        _ = API.User.Get(user.id).subscribeNext { [weak self] user in
            self?.userNameLabel.text = user.name
        }
    }
}

上記のコードはAlamofireRxSwiftを使用しています。
Manager.sharedInstance#rx_requestを使ってます。
多分Manager.sharedInstanceObservableを保持して、リクエストが終わった時点でonCompletedなどが呼ばれていると思うのでその時点で解放されるかと思います。

66
54
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
66
54

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?