LoginSignup
2

More than 5 years have passed since last update.

RxSwiftのDelegateProxyによる拡張はLinuxでは使用できない

Last updated at Posted at 2018-12-13

備忘録として。何か良い手段があれば教えていただきたいです。

まとめ

.rx によるアクセスのために必要な DelegateProxy の Method Swizzling のために Delegate method には @objc メソッドが,Delegate method の @objc func を呼ぶためにクラスには NSObject の継承が必要で,
それらはObjective-Cランタイムを利用するため,(ランタイムを持たない) Linuxでは使用できない

やりたかったこと

あるクラスを RxSwift を import しない状態で,extension によってrxプロパティ経由では変更を通知できるようにしたかった。

具体的には,
時間計測を行う IntervalTimer.swiftmilliseconds プロパティが変化するタイミングで,通常は現在の値しか取れないが,.rx.milliseconds 経由では BehaviorRelay<Int> として Observable に変更を通知できるようにしたい。また,その拡張を外側から実装したい。なお,通知方向は一方向とし,アクセス側からは変更されないものとする。

Non Rx class ---> Rx extension ---> Rx class recieved KVO

という意図から始まった。

class Timer {
    fileprivate(set) var milliseconds: Int
}

extension Timer: ReactiveCompatible {}
extension Reactive where Base: Timer {
    /// Reactive wrapper for `milliseconds` message.
    var milliseconds: BehaviorRelay<Int> {
        // ほげふが
    }
}

let timer = Timer()
timer.milliseconds // -> Int
timer.rx.milliseconds // -> BehaviorRelay<Int>

試したこと

通常の RxCocoa の実装では, DelegateProxy を利用して Delegate method を外側から Reactive struct に適合するように extension を生やし,
ReactiveCompatible によって .rx 記法を利用できるようにした。

なぜ利用できなかったのか

The Swift Linux Port | Swift.org によると,

  • Runtime Introspection: When a Swift class on Apple’s platforms is marked @objc or subclasses NSObject you can use the Objective-C runtime to enumerate available methods on an object or call methods using selectors. Such capabilities are absent because they depend on the Objective-C runtime.

@objcNSObject はObjective-Cランタイムを利用するため,(ランタイムを持たない) Linuxでは使用できない

ということらしい。

どこで利用していたのか

RxCocoa では Delegate method の解決のために NSObject+Rx.swift にて sentMessage() および methodInvoked() が利用できるものの,その引数は Selector でした。
Selector@objc method でしか利用できませんでした (最終的に Method Swizzling に利用され,NSObject が必要)。

.rx によるアクセスのために必要な DelegateProxy の Method Swizzling のために Delegate method には @objc メソッドが,Delegate method の @objc func を呼ぶためにクラスには NSObject の継承が必要で,
それらは Objective-C ランタイムを利用するため,(ランタイムを持たない) Linuxでは使用できない

ということでした。

結局どうしたのか

どうにかできれば登壇材料でしたが,僕の力ではできなかったので素直に rx property を元のクラスに生やしました。
何か良い方法があれば教えていただきたいです......

最後に,頑張って追加した DelegateProxy と,それを泣く泣く消したコミットを添えておきます。お酒のおつまみにでも利用してください。

参考

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
2