iOSエンジニアのつぶやき

毎朝8:30に iOS 関連の技術について1つぶやいています。まれに釣りについてつぶやく可能性があります。

【RxSwift】TextField で .editingChanged の時だけ文字列を取得したい

RxSwiftTextField.text の変更をリッスンしたい時、下記のように書こうとした経験がある人は結構多いかと思います👀

    textField.rx.text
        .subscribe(onNext: { text in
            print(text)
        })
        .disposed(by: disposeBag)

あまり RxSwift に馴染みのない場合、これでも取得できるんじゃないの?と一瞬思うかもしれませんが、上記の例だと .editingChanged 以外の TextField イベントもストリームに流れてきます。

「どのイベントでもいいからとりあえず TextField の変更をリッスンしたい」というユースケースではこのままでもいいかもしれませんが 、テキストの変更を受け取って API にリクエストするなどの状況で使うとなると、不要なイベントがストリームに流れてきてしまうため API のリクエストが意図せず増えてしまう可能性があります。

ちなみに、textField.rx.text がどんな時にイベントを流すかは下記の記事でわかりやすく載っていますので、ぜひ参考にしてみてください。

qiita.com

結論

結論、下記のようにすることで文字列に変更があった場合(.editingChanged) にのみイベントを流すことができます。

    textField.rx.controlEvent(.editingChanged)
        .compactMap {[unowned self] in textField.text }
        .distinctUntilChanged()
        .subscribe(onNext: { text in
            print(text)
        })
        .disposed(by: disposeBag)

textField.rx.controlEvent(.editingChanged)TextField.editingChanged イベントを受け取り、そのイベントを元に TextField.text + compactMap でアンラップした文字列をストリームに流します。また、今回はテキストに変更がなかった場合(同じ文字列を取得した場合)は、イベントを流したくなかったので .distinctUntilChanged()text をフィルターしています。

ちなみに、compactMap() オペレーターは RxSwift 5.0.0 以降でしか使用できないのでご注意を!

github.com

という感じで本日も以上になります👋

その他の記事

yamato8010.hatenablog.com

yamato8010.hatenablog.com

yamato8010.hatenablog.com