ReactiveSwift Signal.Observerにbind出来るようになった🎉

SwiftでMVVMのViewModelを作るとき、Viewからの入力に関していえばViewModelでObservableを保持しそれをObserverとして公開するのが一般的だと思います。

final class ViewModel {
    private let tapLoginSubject = PublishSubject<Void>()
    var tapLogin: AnyObserver<Void> {
        return tapLoginSubject.asObserver()
    }
}

ReactiveSwiftの標準の機能ではObserverに対してBindできないため、RxSwiftと同様にObserverに対してBindするにはExtensionを定義する必要がありました。

しかし10日ほど前にObserverに対してbindする機能が標準で搭載されるようになりました。

github.com

下記のextensionが追加されました。

extension Signal.Observer {
    @discardableResult
    public static func <~
        <Source: BindingSource>
        (observer: Signal<Value, Error>.Observer, source: Source) -> Disposable?
        where Source.Value == Value
    {
        return source.producer.start { [weak observer] in
            switch $0 {
            case .value(let val):
                observer?.send(value: val)
            default: break
            }
        }
    }
}

なのでViewModelを下のように定義して

final class ViewModel {
    struct Input {
        var tapLogin: Signal.Observer<Void>
    }
    let input: Input
   init() {
       let (tapLoginSignal, tapLoginObserver) = Signal<Void, Never>.pipe()
       input = Input(
           tapLogin: tapLoginObserver
       )
   }
}

こんな感じにBindすることができました。

viewModel.input.tapLogin <~ loginButton.reactive.controlEvent(.touchUpInside).map { _ in }

徐々にではありますがRxSwiftよりもReactiveSwift派になってきています。

自分がやりたかった機能が最新のバージョンで取り込まれるとということはなんか安心します(みんな似たよなことをやりたかったということなので)

※私はRxSwiftでの開発経験があるわけでもないし、ReactiveSwift歴も2週間程度です(ドキュメントは基本的に目を通しています)