Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxSwiftでMVVMパターン

 RxSwiftでMVVMパターン

Web技術勉強会#02のLT資料です。
RxSwift+MVVMでシンプルなログインフォームを例として解説しました。

tofu_san0000

June 08, 2019
Tweet

More Decks by tofu_san0000

Other Decks in Technology

Transcript

  1. • next ◦ データが正しく流れてきたというイベント • error ◦ エラー(例外)で異常停止した時に流れるイベント • completed

    ◦ 完了時に発生するイベント 8 RxSwift概要>メソッド>Observable>イベント next next next next error completed
  2. 9 RxSwift概要>メソッド>Observable>イベント Observable.of(“a”, “b”, “c”) .subscribe( x in // “a”,

    “b”, “c” onNext: { value in // イベント発生時の処理 }, onError: { error in // エラー発生時の処理 }, onCompleted: { // 完了時の処理 } )
  3. let disposeBag = DisposeBag() Observable.of(“a”, “b”, “c”) .subscribe( x in

    // “a”, “b”, “c” onNext: { value in // イベント発生時の処理 }, onError: { error in // エラー発生時の処理 }, onCompleted: { // 完了時の処理 } ).disposed(by: disposeBag) 11 RxSwift概要>メソッド>DisposeBag
  4. let disposeBag = DisposeBag() Observable.of(1, 2, 3) .filter { x

    in > 1 } // 2, 3 .map { x in x * 2 } // 4, 6 .flatMap { x in Observable.of(x, x * 2) } // 4, 8, 6, 12 .subscribe( x in onNext: { value in // イベント発生時の処理 }, onError: { error in // エラー発生時の処理 }, onCompleted: { // 完了時の処理 } ) 13 RxSwift概要>メソッド>Operator
  5. LoginButtonの 有効・無効 18 MVVMパターン概要>例>View Model概要 View Model Input Output Email入力

    Password入力 LoginButtonタップ Emailバリデーション Password バリデーション ログイン結果
  6. class LoginViewModel { // output lazy var validEmail: Observable<Bool> lazy

    var validPassword: Observable<Bool> lazy var loginButtonEnable: Observable<Bool> lazy var login: Observable<LoginResponse> } 21 View Model作成>output定義
  7. class LoginViewModel { // output // 省略 // input init(

    email: Observable<String>, password: Observable<String>, loginTap: Observable<Void>, loginAPI: LoginAPI.Type, disposeBag: DisposeBag ) {} } 22 View Model作成>input定義
  8. class LoginViewModel { // output // 省略 // input init(

    email: Observable<String>, password: Observable<String>, loginTap: Observable<Void>, loginAPI: LoginAPI.Type, disposeBag: DisposeBag ) { validEmail = email.map { !$0.isEmpty } } } 23 View Model作成>validEmail
  9. class LoginViewModel { // output // 省略 // input init(

    email: Observable<String>, password: Observable<String>, loginTap: Observable<Void>, loginAPI: LoginAPI.Type, disposeBag: DisposeBag ) { validEmail = email.map { !$0.isEmpty } validPassword = password.map { !$0.isEmpty } } } 24 View Model作成>validPassword
  10. class LoginViewModel { // output    // 省略 // input

    init( // 省略 ) { // 省略 loginButtonEnable = Observable.combineLatest { validEmail, validPassword } .map { $0 && $1 } } } 25 View Model作成>loginButtonEnable
  11. class LoginViewModel { // output    // 省略 // input

    init( // 省略 ) { // 省略 let params = Driver.combineLatest(email, password) { (email: $0, password: $1) } login = loginButtonTap. .withLatestFrom(params) .flatMap { loginAPI.login(with: params) } } 26 View Model作成>loginButtonEnable
  12. class LoginViewModel { // output lazy var validEmail: Observable<Bool> lazy

    var validPassword: Observable<Bool> lazy var loginButtonEnable: Observable<Bool> lazy var login: Observable<LoginResponse> // input init( email: Observable<String>, password: Observable<String>, loginTap: Observable<Void>, loginAPI: LoginAPI.Type, disposeBag: DisposeBag ) { validEmail = email.map { $0.isEmpty } validPassword = password.map { $0.isEmpty } loginButtonEnable = Observable.combineLatest { validEmail, validPassword } .map { $0 && $1 } let params = Driver.combineLatest(email, password) { (email: $0, password: $1) } login = loginBittonTap .withLatestFrom(params) .flatMap { loginAPI.login(with: params) } 27 View Model作成>完成
  13. class LoginViewController: UIViewController { @IBOutlet weak var emailTextField: UITextField! @IBOutlet

    weak var emailErrorLabel: UILabel! @IBOutlet weak var passwordTextField: UITextField @IBOutlet weak var passwordErrorLabel: UILabel! @IBOutlet weak var loginButton: UIButton! } 29 View Controllerl作成
  14. class LoginViewController: UIViewController { // 省略 private let disposeBag =

    DisposeBag() private let vm = LoginViewModel! override func viewDidLoad() { vm = LoginViewModel ( email: emailTextField.rx.text.orEmpty.asObservable, password: passwordTextField.rx.text.orEmpty.asObservable, loginAPI: LoginAPI.self, disposeBag: disposeBag ) } } 30 View Controllerl作成>LoginViewModel作成
  15. class LoginViewController: UIViewController { // 省略 override func viewDidLoad() {

    vm = LoginViewModel ( email: emailTextField.rx.text.orEmpty.asObservable, password: passwordTextField.rx.text.orEmpty.asObservable, loginAPI: LoginAPI.self, disposeBag: disposeBag ) vm.validEmail .bind(to: emailErrorLabel.rx.isHidden) .disposed(by: disposeBag) } } 31 View Controller作成>validEmail
  16. class LoginViewController: UIViewController { // 省略 override func viewDidLoad() {

    vm = LoginViewModel ( // 省略 ) vm.validEmail .bind(to: emailErrorLabel.rx.isHidden) .disposed(by: disposeBag) vm.validPassword .bind(to: passwordErrorLabel.rx.isHidden) .disposed(by: disposeBag) } 32 View Controllerl作成>validPassword
  17. class LoginViewModel: UIViewController { // 省略 override func viewDidLoad() {

    vm = LoginViewModel ( // 省略 ) // 省略 vm.loginButtonEnable .bind(to: loginButton.rx.isEnable) .disposed(by: disposeBag) } } 33 View Controllerl作成>loginButtonEnable
  18. class LoginViewModel: UIViewController { // 省略 override func viewDidLoad() {

    // 省略 vm.login .obseveOn(MainScheduler.instance) .subscribe( onNext: {}, onError: {} ).disposed(by: disposeBag) } } 34 View Controllerl作成>login
  19. class LoginViewModel: UIViewController { // 省略 override func viewDidLoad() {

    // 省略 vm.login .obseveOn(MainScheduler.instance) .subscribe( onNext: { [weak self] self?.showAlert(for: response) }, onError: { [weak self] error self?.showAlert(for: error) } ).disposed(by: disposeBag) } 35 View Controllerl作成>login
  20. class LoginViewModel: UIViewController { @IBOutlet weak var emailTextField: UITextField! @IBOutlet

    weak var emailErrorLabel: UILabel! @IBOutlet weak var passwordTextField: UITextField @IBOutlet weak var passwordErrorLabel: UILabel! @IBOutlet weak var loginButton: UIButton! private let disposeBag = DisposeBag() private let vm = LoginViewModel! override func viewDidLoad() { vm = LoginViewModel ( email: emailTextField.rx.text.orEmpty.asObservable, password: passwordTextField.rx.text.orEmpty.asObservable, loginAPI: LoginAPI.self, disposeBag: disposeBag ) vm.validEmail.bind(to: emailErrorLabel.rx.isHidden).disposed(by: disposeBag) vm.validPassword.bind(to: passwordErrorLabel.rx.isHidden).disposed(by: disposeBag) vm.loginButtonEnable.bind(to: loginButton.rx.isEnable).disposed(by: disposeBag) vm.login .obseveOn(MainScheduler.instance) .subscribe(onNext: { [weak self] self?.showAlert(for: response) }, onError: { [weak self] error self?.showAlert(for: error) }).disposed(by: disposeBag) } } 36 View Controllerl作成>完成