I'm very new to RxSwift and RxCocoa and I've recently made heavy use of Variable
because of how convenient it is to just push mutations into the Variable
through its value. Now that it is deprecated I'm trying to understand how best to use BehaviorRelay
instead. There's an Rx-y way of doing what I want to do, but I'm having a hard time landing on it.
What I want is to put an instance of struct-based model behind a ViewModel and observe changes to it and bind UI elements in such a way that I can mutate that model through the BehaviorRelay
.
The model is simple:
struct Pizza {
var name: String
var price: Float
}
So is the View Model:
final class PizzaViewModel {
let pizzaRelay = BehaviorRelay<Pizza>(value: Pizza(name: "Sausage", price: 5.00))
init(pizza: Pizza) {
pizzaRelay.accept(pizza)
// I feel like I'm missing something Rx-like here...
}
}
Then somewhere you would maybe bind a UITextField to the BehaviorRelay like so:
viewModel
.pizzaRelay
.asObservable()
.map { $0.name }
.bind(to: nameTextField.rx.text)
.disposed(by: disposeBag)
The question becomes: if you need to push values from the text field back into the BehaviorRelay how should that work?
nameTextField
.rx
.controlEvent([.editingChanged])
.asObservable()
.subscribe(onNext: { [weak self] in
guard let self = self else { return }
if let text = self.nameTextField.text {
self.viewModel.pizzaRelay.value.name = text // does not compile because value is a let
}
}).disposed(by: disposeBag)
I'm probably not using the correct types here or I'm not thinking in the correct Rx-fashion in-terms of streams of inputs/outputs, but I'm curious how others might approach this problem?
Other things I've considered:
- Just reconstructing a new
Pizza
in the.subscribe
using current value in theBehaviorRelay
, mutating the name and then.accept
-ing that back into the relay. That doesn't feel exactly right, though. - Creating individual
BehaviorRelay
's for each property I want to mutate on myPizza
, then.accept
-ing values for each property and then usingcombineLatest
on all those relays and returning aObservable<Pizza>
. But that feels clunky also.
How should this work in an ideal world? Am I thinking about this incorrectly? Help! My head hurts.