NSObject-Rxの実装を紐解きます。
RxSwiftを利用していれば、おそらく利用したことのあるライブラリ、RxSwiftCommunity/NSObject-Rx。
一応解説しておくと、NSObjectのサブクラスであれば、DisposeBagを宣言する必要なく利用することができるという便利な代物です。
RxSwiftで開発をしているととても良く使うライブラリの一つではないでしょうか。
今回、ひょんなことからこのライブラリがどのようにしてdisposeBagを実装しているのかを確認してみたくなって、びっくりしたので、まとめておきます。
Swiftの機能のみを利用した実装ではない。
今回話しているRxSwiftCommunity/NSObject-RXは、Swiftの機能のみを利用した実装にはなっていません。
NSObject-Rxの実体ファイルは下記ファイルなのですが、結構無茶苦茶やってますね。
大まかな流れは、
-
ReactiveProtocolのデフォルト拡張をBase: AnyClassに指定(すべてのクラスでデフォルト拡張される) -
Objective-Cの
メンバ変数追加ができるAssociated Objectというびっくり黒魔術を利用してDisposeBagを宣言
(SwiftでObjective-Cの黒魔術ってどうなった?: https://qiita.com/fmtonakai/items/e9036dec4af2609b5715) -
初回アクセス時には生成、セット時には
setter内部でセットされたdisposeBagをAssociated Object経由でプロパティかのように保持 -
disposeBagの生成、アクセス処理は
objc_sync_enter、objc_sync_exitで強制同期。
結構すごい実装になってました。
ちなみになんですが、Associated ObjectはピュアSwiftだと動作しないようなので、Ubuntuとかで開発する場合は、うまくいかない感じだと思われます。
読み解いてみて
Objective-C由来の黒魔術がこんなところで生かされていたのが結構驚きでした。