alphonse
alphonse

Reputation: 717

How to make condition logic and reset observable with RXSwift and MVVM

I'm new with RXSwfit, and trying to build simple count app with RXSwift and MVVM.

view

  1. count label how many times tapped + button.
  2. increase button
  3. reset button

conditions

  1. count starts with zero.
  2. increase button's isEnabled should be false if number reaches to 10
  3. when reset button is tapped, number should be set to zero , and if + button's isEnabled is false, it should be set true.

So I created ViewModel which has a number Observable as BehavioSubject. And some logic methods.

   class CounterViewModel {
   
       var number = BehaviorSubject<Int>(value: 0)
    
       func changeCount(_ number: Int) {
           self.number.onNext(number)
       }
    
       func resetCount() {
           //reset number to zero
       }
   }

And in ViewController I bound number observable with countLabel.text.

And when new data comes to number observable, It adds new data with scan, and sets result to countLable.text

When I tap increaseButton, It calls method from viewModel and passes parameter 1.

In changeCount method, it passes new data to observable.

class ViewController: UIViewController {

    @IBOutlet weak var countLabel: UILabel!
    @IBOutlet weak var increaseButton: UIButton!
    @IBOutlet weak var resetButton: UIButton!

    let viewModel = CounterViewModel()
    var disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        bind()
    }

    func bind() {
        viewModel.number
        .scan(0, accumulator: +)
        .map { "\($0)" }
        .bind(to: countLabel.rx.text)
        .disposed(by: disposeBag)
    }

    @IBAction func increaseButtonPressed(_ sender: Any) {
        viewModel.changeCount(1)
    }

    @IBAction func resetButtonPressed(_ sender: Any) {
        viewModel.resetCount()
      }

}

The problem is,

I don't know how to make conditions to this observable sequence, and how to reset number and state of button.

How can I do this?

Upvotes: 0

Views: 1269

Answers (1)

congnd
congnd

Reputation: 1274

I think if you use the scan operator inside the view controller like that, you have no way to reset the value. Since your number sequence in your model doesn't hold the current value.

I'd like to suggest you control the increasing logic inside your view model. Your number sequence now holds the current value but not just emit a new number 1 like your current implementation.

Then inside your view controller, you can use the same sequence to control both your label and your button.

class CounterViewModel {
    var number = BehaviorRelay<Int>(value: 0)

    func increaseCount() {
        number.accept(number.value + 1)
    }

    func resetCount() {
        number.accept(0)
    }
}

And now your bind function will be like this:

func bind() {
    viewModel.number
        .map { "\($0)" }
        .bind(to: countLabel.rx.text)
        .disposed(by: disposeBag)

    viewModel.number
        .map { $0 >= 10 ? false : true }
        .bind(to: increaseButton.rx.isEnabled)
        .disposed(by: disposeBag)
}

Upvotes: 1

Related Questions