記録。

めも。

textField.rx.textではbindできなかった

最近は、以前挫折したRxSwiftをもう一度勉強中な感じです。

RxSwiftやMVVM周りでわかったことは今後別の記事にあげていこうと思っています。

今日は小ネタな感じで、少しつまづいたことを書いていこうと思います。

textField.rx.text.bindはエラーと言われてしまう

UITextFieldのObservableをViewModel側のObserverにbindしようとした時、 なぜかできませんでした。

f:id:jksdaba:20181209103823p:plain

※bindしようとしている対象はObserverです。(ViewModel側で以下のように宣言して公開しています)

// viewModel

import RxSwift
import RxCocoa
import Foundation

class viewModel {

  private let titleEditStream = PublishSubject<String>()
  
  var titleEdit: AnyObserver<String> {
      return titleEditStream.asObserver
  }

  //以下省略

}

というように、textFieldに入力されたら(イベントが流れ始めたら)、viewmodel側にイベントストリームを流したいと考えていたのですが、 上記の画像のようにエラーになってしまいました。

理由

どうしてエラーが発生するのかというのは、単純でした。 流れてくるイベント(この場合だと入力された文字列)はStringではなく、String?だったからです。

これはRxを使用していなくても標準のもので、UITextField.textの型はString?です。

宣言しているObserverの方の型(ジェネリクスの部分)はStringのため、String?→Stringに変える必要があります。

どうするか

RxにはorEmptyというpropertyがあります。 それを使用することで、String?→Stringに変換してくれます。

orEmptyがどのように実装されているのかはこんな感じでした。

f:id:jksdaba:20181209105349p:plain

※RxCocoa/ControlProperty.swift

コードの中のコメントにも書いているように、String? → Stringに変換してくれています。 実際は、mapで変換していましたね。

let values: Observable<String> = original._values.map{ $0 ?? "" }

画像のソースコードについて
※valuesはObservableです。(returnでObservableに変換されています)
※valuesSinkはObserverです。(AnyObserver, returnでAnyObserverに変換されています)

f:id:jksdaba:20181209110656p:plain

ということで、orEmptyを使用することでbind(to: ~)を使用してもエラーが表示されなくなりました。

f:id:jksdaba:20181209110512p:plain