Search code examples
iosswiftmvvmbindingrx-swift

Bind a tuple or string in view controller to view model with RXSwift


I need to bind a tuple(String, Int) to view model

class ViewModel {

var firstAttempt = PublishSubject<(password: String, count: Int)>()
var isValidFirstAttempt: Observable<Bool> {
    return firstAttempt.asObservable().map{
        if $0.count < 4 {
            self.onShowError.onNext("error")
            return false
        }
        return true
    }
}
let onShowError = PublishSubject<String>()

View controller

class ViewController: UIViewController {

var viewModel =  ViewModel()
var firstAttempt = BehaviorRelay<(value:String, count: Int)>(value: ("", 0))

func bindControllerComponent() {
    firstAttempt.bind(to: viewModel.firstAttempt).disposed(by: disposeBag)
    viewModel.firstAttempt.bind(to: firstAttempt).disposed(by: disposeBag)
}

with executing self.firstAttempt.accept(("password", 4)) in view controller I want to get changes in view model is it possible?


Solution

  • This should help you out:

    class ViewModel {
    
        let firstAttempt = PublishSubject<(password: String, count: Int)>()
    
        var isValidFirstAttempt: Observable<Bool> {
            return firstAttempt.map { 3 < $0.count }
        }
    
        var onShowError: Observable<String> {
            return firstAttempt.filter { $0.count < 4 }.map { _ in "error" }
        }
    }
    
    class ViewController: UIViewController {
    
        var viewModel =  ViewModel()
        let firstAttempt = BehaviorRelay<(password: String, count: Int)>(value: ("", 0))
        let disposeBag = DisposeBag()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            firstAttempt.bind(to: viewModel.firstAttempt).disposed(by: disposeBag)
    
            viewModel.isValidFirstAttempt
                .bind(onNext: { print("isValid?", $0) })
                .disposed(by: disposeBag)
    
            viewModel.onShowError
                .bind(onNext: { [weak self] message in
                    let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                    self?.present(alert, animated: true, completion: nil)
                })
                .disposed(by: disposeBag)
        }
    }