[RxSwift] CombineLastest

Junyoung Park·2022년 8월 31일
0

RxSwift

목록 보기
7/25
post-thumbnail
post-custom-banner

RxSwift Beginners Episode 7 - Login form validations. combineLatest and withLatestFrom operators

CombineLastest

구현 목표

  • 두 개 이상의 옵저버를 동시에 컴바인한 combineLastest 사용
  • RxSwift를 통해 UIButton의 특정 액션 함수가 아니라 구독을 통해 특정 함수 실행하기

구현 태스크

  1. 유저 아이디, 비밀번호 텍스트 필드를 통해 두 개의 옵저버 구현
  2. 두 개의 옵저버를 결합한 combineLastest 구현
  3. 결합한 옵저버의 관측값에 따라 로그인 여부를 판단하는 함수 실행

핵심 코드

    private func setObservers() {
        let observer1 = userNameTextField.rx.text.orEmpty
        let observer2 = passwordTextField.rx.text.orEmpty
        let observerCombined = Observable.combineLatest(observer1, observer2)
        loginButton.rx.tap
            .withLatestFrom(observerCombined)
            .subscribe(onNext: { (userName, password) in
                self.login(userName, password)
            })
            .disposed(by: disposeBag)
    }
  • 옵저버를 아이디, 패스워드 텍스트 필드의 텍스트에 각각 하나씩 총 두 개를 구현
  • 두 개의 옵저버를 Observable.combineLatest 메소드를 통해 한 개의 옵저버로 구현
  • 특정 버튼(loginButton)이 탭했을 경우 RxSwift 메소드를 통해 위의 결합한 옵저버 값을 관찰하고, 결과값을 구독해 로그인 여부를 판단하는 login() 메소드 실행

소스 코드

import Foundation
import UIKit
import RxSwift
import RxCocoa

class LoginViewController: UIViewController {

    @IBOutlet weak var userNameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var loginButton: UIButton!
    let disposeBag = DisposeBag()
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Login"
        setObservers()
    }
    
    private func setObservers() {
        let observer1 = userNameTextField.rx.text.orEmpty
        let observer2 = passwordTextField.rx.text.orEmpty
        let observerCombined = Observable.combineLatest(observer1, observer2)
        loginButton.rx.tap
            .withLatestFrom(observerCombined)
            .subscribe(onNext: { (userName, password) in
                self.login(userName, password)
            })
            .disposed(by: disposeBag)
    }
    
    private func login(_ userName: String, _ password: String) {
        if isLoginPossible(userName, password) {
            guard let foodTableVC = storyboard?.instantiateViewController(withIdentifier: "FoodListViewController") as? ViewController else {
                invalidMessage()
                return
            }
            navigationController?.pushViewController(foodTableVC, animated: true)
        } else {
            invalidMessage()
        }
    }
    
    private func invalidMessage() {
        let alert = UIAlertController(title: "Warning!", message: "Invalid ID or PW!", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        present(alert, animated: true, completion: nil)
    }
    
    private func isLoginPossible(_ userName: String, _ password: String) -> Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        let emailTest = NSPredicate(format: "SELF MATCHES[c] %@", emailRegEx)
        let emailValid: Bool = emailTest.evaluate(with: userName)
        let passValid: Bool = (password != "" && password.count >= 6)
        return emailValid && passValid
    }
}
  • RxSwift를 쓰지 않는다면 loginButton이라는 UIButton에 탭을 통해 함수를 추가하거나, IBOutlet 함수로 login을 등록해야 한다.

구현 화면

RxSwift를 통해 특정 UI 버튼의 탭과 같은 UI 행동 역시 컨트롤할 수 있다는 것에 놀랐다.

profile
JUST DO IT
post-custom-banner

0개의 댓글