どういう問題か?
タイトルで説明しきれなかったのでここで問題点について説明いたします。
Objective-Cで開発されたプロジェクトを部分的にSwiftに移植していく場合は、Swift側でObjective-Cクラスのextensionとしてメソッドを定義する方法があります。
参考: 【Swift】Objective-Cで書いたクラスをメソッド単位で少しずつSwiftへ移行する方法
勉強会などでiOSアプリエンジニアに話を聞いていると、Objective-CとSwift混在のアプリはまだまだあるのではないかという印象なので、この手法のお世話になっている人もいるのではないでしょうか。
一方、RxSwiftを使っている場合はDisposeBagのインスタンスをUIViewControllerのプロパティとして持たせておいて、ViewController消滅時にDisposeさせる手法が広く扱われていると思います。
しかしSwiftのextension内ではStored property
を定義することができないため、DisposeBagをViewControllerクラスインスタンスの寿命と連動させることが困難です。
解決方法
Associated Object
を使うことで、SwiftのComputed property
を用いてもDisposeBagをインスタンスに保持させることができます。Associated Object
下記の記事などで解説されているので参照ください。
参考: [Objective-C] Associated Objectを使いランタイムにプロパティを追加する
ざっくりいうと、プロパティとは別の仕組みでオブジェクトに動的にデータを設定するための仕組みです。
とはいえ、こんな黒魔術みたいなのを自分で書きたくないという人にお勧めのライブラリがありました。NSObject+Rx というライブラリを入れることで下記のようにDisposeBagを生成&取得できます
extension HogeViewController {
func configureBinding() {
thing
.bind(to: otherThing)
.disposed(by: self.rx.disposeBag)
}
}
self.rx.disposeBag
の部分がNSObject+Rxによって追加されたプロパティです。このプロパティは内部でAssociated Object
としてDisposeBag
のインスタンスを保持するように実装されたComputed property
です。初回のgetでDisposeBagのインスタンスを生成して保持するようになっています。(2018/05/10現在の情報です。このライブラリの実装は紆余曲折もあったらしく、今後変わる可能性も考えられます)
まとめ
Associated Object
でできます。
ライブラリがすでにあるのでNSObject+Rx を使えます。
NSObject+Rxの目的はこのような目的ではなく、「わざわざDisposeBagを各クラスのプロパティとして定義する手間を省く」ためのものらしいので、今回のような用途の解決策として検索していても見つかりにくいように思いました。検索で見つかる可能性が増えるためにこの記事を書きました。
補足
この記事の内容は下記のブログ記事の内容の一部としても取り上げましたが、記事のタイトルからこの問題の解決を連想しにくいと思いました。そのためこの問題のみを抜き出して記事化しました。