How to bind rx_tap (UIButton) to ViewModel?

后端 未结 3 868
我在风中等你
我在风中等你 2021-02-05 15:52

I have authorization controller with 2 UITextField properties and 1 UIButton. I want to bind my View to ViewModel but don\'t know how to to do it. This is my AuthorizatioVC.swi

3条回答
  •  我在风中等你
    2021-02-05 16:20

    You can turn the taps on the UIButton into an Observable and hand it to the ViewModel along with the two Observables from the UITextFields.

    This is a small working example for your scenario. (I used a small auth client mock class to simulate the response from the service):

    The ViewController:

    import UIKit
    import RxSwift
    import RxCocoa
    
    class ViewController: UIViewController {
    
        let loginTxtField = UITextField(frame: CGRect(x: 20, y: 50, width: 200, height: 40))
        let passwordTxtField = UITextField(frame: CGRect(x: 20, y: 110, width: 200, height: 40))
        let loginButton = UIButton(type: .RoundedRect)
    
        let disposeBag = DisposeBag()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.backgroundColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1)
    
            loginTxtField.backgroundColor = UIColor.whiteColor()
            view.addSubview(loginTxtField)
    
            passwordTxtField.backgroundColor = UIColor.whiteColor()
            view.addSubview(passwordTxtField)
    
            loginButton.setTitle("Login", forState: .Normal)
            loginButton.backgroundColor = UIColor.whiteColor()
            loginButton.frame = CGRect(x: 20, y: 200, width: 200, height: 40)
            view.addSubview(loginButton)
    
            // 1
            let viewModel = ViewModel(
                withLogin: loginTxtField.rx_text.asObservable(),
                password: passwordTxtField.rx_text.asObservable(),
                didPressButton: loginButton.rx_tap.asObservable()
            )
    
            // 2
            viewModel.authResponse
                .subscribeNext { response in
                    print(response)
                }
                .addDisposableTo(disposeBag)
        }
    }
    

    These are the two interesting parts:

    // 1: We inject the three Observables into the ViewModel when we initialize it.

    // 2: Then we subscribe to the ViewModel's output to receive the Auth model after the login was done.

    The ViewModel:

    import RxSwift
    
    struct Auth {
        let token: String
    }
    
    struct AuthResponse {
        let token: String
    }
    
    class ViewModel {
    
        // Output
        let authResponse: Observable
    
        init(withLogin login: Observable, password: Observable, didPressButton: Observable) {
            let mockAuthService = MockAuthService()
    
            // 1
            let userInputs = Observable.combineLatest(login, password) { (login, password) -> (String, String) in
                return (login, password)
            }
    
            // 2
            authResponse = didPressButton
                .withLatestFrom(userInputs)
                .flatMap { (login, password) in
                    return mockAuthService.getAuthToken(withLogin: login, mergedHash: password)
                }
                .map { authResponse in
                    return Auth(token: authResponse.token)
                }
        }
    }
    
    class MockAuthService {
        func getAuthToken(withLogin login: String, mergedHash: String) -> Observable {
            let dummyAuthResponse = AuthResponse(token: "dummyToken->login:\(login), password:\(mergedHash)")
            return Observable.just(dummyAuthResponse)
        }
    }
    

    The ViewModel gets the 3 Observables in its init method and connects them to its output:

    // 1: Combine the latest value of the login text field and the latest value of the password text field into one Observable.

    // 2: When the user presses the button, use the latest value of the login text field and the latest value of the password text field and pass that to the auth service using flatMap. When the auth client returns a AuthResponse, map that to the Auth model. Set the result of this "chain" as the authResponse output of the ViewModel

提交回复
热议问题