コネヒト開発者ブログ

コネヒト開発者ブログ

RxSwift.Variableはdeprecatedになりました

こんにちは、ガチエリアS帯のリードエンジニアの田村(@Utmrer)です。他のルールもS帯にいくため、Splatoon2サントラを聴きながら日々コーディングをしております。
この記事はConnehito Advent Calendar 2017の4日目の記事です。

今日はRxSwiftのコードを覗いていたら気づいたことを書きました。
(2017年12月4日現在の情報です)

Variableとは

VariableはRxSwiftで提供されているBehaviorSubjectのwrapperで値の取り出しや代入を直感的に扱うことができるSubjectの1つです。
MVVMでステートフルなViewModelのpropertyとして使っている人が多いのではないでしょうか。

// Example
class VM {
    let name = Variable("")
}
class VC {
    func f() {
        textField.rx.text.orEmpty
            .bind(to: vm.name)
            .disposed(by: disposeBag)
    }
}

RxSwift4でVariableはしれっとdeprecatedに

ある日RxSwift repositoryのコードを読んでいたらDeprecated.swiftという非推奨のAPIをまとめたファイルを見つけ、Variableが記載されているのを見つけました。
Warningが出ていないので気づけなかったのですが、Warningを出していないのは利用者が多いことなどが理由のようです。*1
ではVariableが非推奨になった時代に私たちはどうすればいいのでしょう。

安全なBehaviorSubjectであるBehaviorRelay

Variableのdeprecatedと同時に追加されたBehaviorRelayはBehaviorSubjectのwrapperでerrorの流れることが無い、安全なBehaviorSubjectです。この点においてVariableとほぼ同じ特性を持ちます。
Variableではvalue propertyのsetter/getterで値の操作を行っていたのが、BehaviorRelayでは下記のようなaccept() methodとvalue propertyでアクセスします。

let relay = BehaviorRelay<Int>(value: 0)
relay.asDriver()
    .drive(onNext: { value in
        print(value)
    })
    .disposed(by: disposeBag)
relay.accept(1)
print(relay.value)

Variableが非推奨になったので、同様の性質をもつBehaviorRelayに移行していくのが正道となるでしょう。

BehaviorRelayはRxCocoa

今までVariableはRxSwift moduleの一部でしたが、BehaviorRelayはRxCocoa moduleの一部になっています。BehaviorRelayと同時期に実装された安全なPublishSubjectであるPublishRelayもRxCocoaです。
これは「Relayは特定の環境で求められるものであり、Reactive Extensionsのコンセプト外である」というのが理由のようです。*2
ではRxCocoaに含まれるのが適切なのでしょうか?RelayにはCocoaへの依存はありません。ちなみに、これらRelayの設計元になったと思われるRxJavaのRxRelayはRxJavaのユーティリティという立ち位置でRxJava, RxAndroidには実装されていません。
このままRxCocoaに含まれていくような気がしますが、RxRelayとして分離されることがあるかもしれません。

BehaviorRelayへの移行はやるべき?

今すぐにでもVariableからBehaviorRelayへの移行を行うべきか、というと個人的にはちょっと待とうと思っています。なぜならば、Variableで提供されていたbind(to:)というmethodがまだBehaviorRelayには提供されていないからです。*3 RxSwiftの中の人も「ちゃんと移行方法を決めたら@availability付けて本当にdeprecatedにするよ」と言っているのでそれまで待ってもいいかなと思っています。*4
下記のようにextensionを書くことでbind(to:)を使うこともできるので待てなくなったら移行します。(副作用がちょっとわからないのでまだやってないのですが)

extension BehaviorRelay: ObserverType {
    public func on(_ event: Event<Element>) {
        switch event {
        case .next(let value):
            accept(value)
        default:
            break
        }
    }
}

まとめ

以上、RxSwift4でのVariableとBehaviorRelayについてでした。@availabilityが付くと大量のwarningが出る可能性があるので備えておきたいですね。 明日は@fortkleによるファビュラスマックスな5日目の記事をお送りします。

qiita.com