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

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

## まとめ

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

## やりたかったこと

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

具体的には，
時間計測を行う [IntervalTimer.swift](https://github.com/YutoMizutani/OperantKit/blob/master/Sources/Application/Timer/IntervalTimer.swift) の `milliseconds` プロパティが変化するタイミングで，通常は現在の値しか取れないが，`.rx.milliseconds` 経由では `BehaviorRelay<Int>` として Observable に変更を通知できるようにしたい。また，その拡張を外側から実装したい。なお，通知方向は一方向とし，アクセス側からは変更されないものとする。

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

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

```swift
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](https://swift.org/blog/swift-linux-port/) によると，

> * **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.

*`@objc` や `NSObject` はObjective-Cランタイムを利用するため，(ランタイムを持たない) Linuxでは使用できない* 

ということらしい。

## どこで利用していたのか

[RxCocoa](https://github.com/ReactiveX/RxSwift) では Delegate method の解決のために [NSObject+Rx.swift](https://github.com/ReactiveX/RxSwift/blob/master/RxCocoa/Foundation/NSObject%2BRx.swift) にて [`sentMessage()`](https://github.com/ReactiveX/RxSwift/blob/master/RxCocoa/Foundation/NSObject%2BRx.swift#L136) および [`methodInvoked()`](https://github.com/ReactiveX/RxSwift/blob/master/RxCocoa/Foundation/NSObject%2BRx.swift#L165) が利用できるものの，その引数は `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 と，それを泣く泣く消したコミットを添えておきます。お酒のおつまみにでも利用してください。

https://github.com/YutoMizutani/OperantKit/commit/f49d573e04810a15f4865f2ac98d671c926c55ba

https://github.com/YutoMizutani/OperantKit/commit/80f8fcedd733c45b4b2204995a515dcc80569383

## 参考

* [GitHub - ReactiveX/RxSwift: Reactive Programming in Swift](https://github.com/ReactiveX/RxSwift)
* [The Swift Linux Port | Swift.org](https://swift.org/blog/swift-linux-port/)
* [DelegateProxyType.swift | ReactiveX/RxSwift](https://github.com/ReactiveX/RxSwift/blob/53cd723d40d05177e790c8c34c36cec7092a6106/RxCocoa/Common/DelegateProxyType.swift)
* [SwiftでのMethod Swizzlingについて](https://blog.waft.me/2015/08/20/method-swizzling/)
* [Swift で Class-Only Protocol を定義する](https://qiita.com/lovee/items/a686e11f00b31323e683)
* [SwiftのExtensionをモダンでオシャレに実装する](https://qiita.com/motokiee/items/e8f07c11b88d692b2cc5)
* [Swift でデリゲートを実装する方法](https://ez-net.jp/article/BE/OeNCbTlM/NpjEbGA6K2cA/)
* [デリゲートメソッドをRxSwift対応させる方法](http://tiny-wing.hatenablog.com/entry/2016/04/18/085621)