The Pragmatic Ball boy

iOSを中心にやってる万年球拾いの老害エンジニアメモ

RxSwiftでログイン画面のサンプル実装

ユーザー名とパスワードを規定の文字数以上入力するとログインボタンが有効になるViewControllerをRxSwiftを使って実装してみました。

SwiftBondしか使ったことなく初めてRxSwiftを使ってみた感想としては、RxSwiftのほうが似たようなものがたくさんあり学習コストは高いなと思いました。 Observableについて見てみると、RxSwiftのほうはReactiveXのObservableであるためonNext,onCompleted,onErrorがありますが、SwiftBondのほう単に変化を見るだけでいわばonNextしかないようなものなので、その辺で差がメリット・デメリットにあらわれているのかなと。

ViewController

import UIKit
import RxSwift
import RxCocoa

class LoginViewController: UIViewController {

  @IBOutlet weak var inputTextField: UITextField!
  @IBOutlet weak var loginButton: UIButton!
  @IBOutlet weak var passwordTextField: UITextField!

  private let viewModel = LoginViewModel()
  private let disposeBag = DisposeBag()

  override func viewDidLoad() {
    super.viewDidLoad()

    addBindings()
  }

  private func addBindings() {
    // username
    // UITextField -> ViewModel
    inputTextField.rx_text
      .bindTo(viewModel.userName)
      .addDisposableTo(disposeBag)
    // ViewModel -> UITextField
    viewModel.userName.asObservable()
      .observeOn(MainScheduler.instance)
      .bindTo(inputTextField.rx_text)
      .addDisposableTo(disposeBag)

    // password
    // UITextField -> ViewModel
    passwordTextField.rx_text
      .bindTo(viewModel.password)
      .addDisposableTo(disposeBag)
    // ViewModel -> UITextField
    viewModel.password.asObservable()
      .observeOn(MainScheduler.instance)
      .bindTo(passwordTextField.rx_text)
      .addDisposableTo(disposeBag)

    // UIButtonのタップイベント
    loginButton.rx_tap
      .subscribeNext { [weak self] in
        self?.viewModel.login()
      }
      .addDisposableTo(disposeBag)
    // ViewModel -> UIButtonのenabled
    viewModel.enableLoginButton
      .bindTo(loginButton.rx_enabled)
      .addDisposableTo(disposeBag)
  }
}

ViewModel

import Foundation
import RxSwift
import RxCocoa

class LoginViewModel {
  let userName = Variable("")
  let password = Variable("")
  let enableLoginButton: Observable<Bool>

  init() {
    // 3文字以上だったらボタンをenbaleにする
    enableLoginButton = Observable.combineLatest(userName.asObservable(), password.asObservable()) {
      $0.0.characters.count >= 3 && $0.1.characters.count >= 3
    }
  }

  func login() {
    print("user=", userName.value)
    print("password=", password.value)
    userName.value = ""
    password.value = ""
  }
}

VariableよりDriverとかのほうがよかったのかとか、VariableをsubscribeするならsubscribeNextじゃなくてsubscribeでもいいんじゃないかなとか色々怪しい気がするんですが、もうちょっと勉強したいと思います