Login에 RxSwift 적용하기

JinSeok Hong·2021년 7월 5일
0

Login에 RxSwift 적용하기

이번 시간에는 지금까지 공부했던 RxSwift를 직접 이용하는 시간을 가졌다.
아래 예제는 로그인에 관한 내용인데 아이디, 비밀번호를 input으로 받고 이에 따라 로그인이 가능한지 검증하는 실습이었다.

자세한 내용은 아래 코드의 주석을 통해 이해해보자.

참고자료 : https://www.youtube.com/watch?v=w5Qmie-GbiA&t=6292s



import RxCocoa
import RxSwift
import UIKit

class ViewController: UIViewController {
    var disposeBag = DisposeBag()
    
    // MARK: - IBOutlet
    
    @IBOutlet var idField: UITextField!
    @IBOutlet var pwField: UITextField!
    @IBOutlet var loginButton: UIButton!
    @IBOutlet var idValidView: UIView!
    @IBOutlet var pwValidView: UIView!

    // MARK: - Properties
    
    let idInputText : BehaviorSubject<String> = BehaviorSubject(value : "")
    let idValid : BehaviorSubject<Bool> = BehaviorSubject(value : false)
    let pwInputText : BehaviorSubject<String> = BehaviorSubject(value : "")
    let pwValid : BehaviorSubject<Bool> = BehaviorSubject(value : false) 
    
    // MARK: - ViewCycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        bindInput()
        bindOutput()
        //처음 뷰가 시작되면 bind 를 설정해준다. bind는 subscribe와 거의 같다고 볼 수 있는데 subscribe와 조금 다른 점은 어떠한 error인지 따로 처리를 하지 않는다는 점이다. 그냥 간단한 subscribe라고 이해하면 좋을거 같다. 
    }

    // MARK: - Bind UI
    
    func invert(_ b : Bool) -> Bool { return !b } 
    
    private func bindInput() {
        // id input +--> check valid --> bullet 
        //          |
        //          +--> button enable
        //          |
        // pw input +--> check valid --> bullet
        // 전체적인 input 로직이다. 아이디와 비밀번호 입력 값에 따라 각각의 valid를 검사하고 만약 false라면 조건에 맞지 않는다고 표현해주는 것이다. 만약 두 입력 값 모두 조건에 성립한다면 버튼을 활성화 상태로 변경시켜준다.
        
        idField.rx.text.orEmpty
            .bind(to: idInputText)//텍스트 필드에 들어오는 값 바인드 
            .disposed(by: disposeBag)
        
        idInputText
            .map(to: checkEmailValid) //checkEmailValid를 통해 idInput값 valid를 검사한다.
            .bind(to : idValid) // 위의 stream을 통해 얻은 값을 idValid에 바인드해준다.
            .disposed(by: disposeBag) // 끝났으면 Dispose
        
        pwField.rx.text.orEmpty
            .bind(to: pwInputText)
            .disposed(by: disposeBag)
            
        pwInputText
            .map(to: checkPasswordField) //마찬가지로 checPasswordValid를 통해 pwInput값 valid를 검사한다.
            .bind(to : pwValid) // 위의 stream을 통해 얻은 값을 pwValid에 바인드 해준다.
            .disposed(by: disposeBag)
    }
    
    private func bindOutput(){
    
        idValid.subsribe(onNext: { b in self.idValidView.isHidden = b})
            .disposed(by: disposeBag)
            
        pwValid.subsribe(onNext: { b in self.pwValidView.isHidden = b})
            .disposed(by: disposeBag)
            
        // 위의 idValid, pwValid 두 인스턴스 모두 위의 input에 들어오는 값을 subscribe하고 있다. 따라서 값이 들어오는 것에 따라 view.isHidden의 상태가 바뀔 것이다.
        
        Observable.combineLatest(idValid, pwValid, resultSelector: {$0 && $1})
            .subscribe(onNext: { b in self.loginButton.isEnabled = b })
            .diposed(by: disposeBag)
        //combinLatest의 경우 두 개의 observable을 결합해준다. 이 의미로 로그인을 한다면 아이디, 비밀번호 두 가지 조건이 모두 만족해야한다. 이에 따라 만약 둘 중 하나가 emit 될 경우 두 가지의 가장 최근 Item을 결합하여 emit해준다. 따라서 그때그때 로그인 조건이 만족하는지 확인해줄 수 있다. 
    }

    // MARK: - Logic
    
    private func checkEmailValid(_ email: String) -> Bool {
        return email.contains("@") && email.contains(".")
    }

    private func checkPasswordValid(_ password: String) -> Bool {
        return password.count > 5
    }
}

0개의 댓글