Home > OS >  Swift 5: How to get the value of a BehaviorRelay and binding with RxSwift and MVVM
Swift 5: How to get the value of a BehaviorRelay and binding with RxSwift and MVVM

Time:01-21

I'm trying to get the amount value from the service in the View Model, and then bind it in the ViewController to an amountLabel.

This is my ViewModel:

class AmountViewModel {
    
    private let accountService: AccountManagerProtocol        
    
    let _amount = BehaviorRelay<Int>(value: 0)
    let amount: Observable<Int>
        
    private let disposeBag = DisposeBag()
   
    init(accountService: AccountManagerProtocol = AccountManager()) {

        self.accountService = accountService
    
        amount = _amount.asObservable()
        
        getAmount()   
    }

    func getAmount(){
        accountService.getAccount()
            .map{ $0.amount ?? 0 }
            .bind(to: _amount)
            .disposed(by: disposeBag)
    }
}

This is my ViewController, I did something like this, to obtain the amount of the viewModel, but I feel that it is not the best way, I would like to obtain the value of amount and be able to bind it to amountLabel in a simpler way.

private extension AmountViewController {
    private func bindViewModel() {
        amountView.titleLabel.text = viewModel.title
               
        //Get Amount
        viewModel.amount
            .observe(on: MainScheduler.instance)
            .withUnretained(self)
            .subscribe(onNext: { owner, amount in
                if let amountString = amount.currencyToString() {
                owner.inputAmountView.amountLabel.text = "BALANCE: \(amountString)"
                }
            })
            .disposed(by: disposeBag)
 }   

CodePudding user response:

Here is the most obvious simplification:

class AmountViewModel {
    let amount: Observable<Int>
    
    init(accountService: AccountManagerProtocol = AccountManager()) {
        amount = accountService.getAccount()
            .map { $0.amount ?? 0 }
    }
}

private extension AmountViewController {
    private func bindViewModel() {
        viewModel.amount
            .compactMap { $0.currencyToString().map { "BALANCE: \($0)"} }
            .observe(on: MainScheduler.instance)
            .bind(to: inputAmountView.amountLabel.rx.text)
            .disposed(by: disposeBag)
    }
}

But I think I would move the code in the compactMap closure into the view model...

  •  Tags:  
  • Related