How to observe Bool properties with RxSwift?
Solution 1
Don't use Bool
and rx_observe
. Instead, use a Subject
such as Variable<Bool>
.
let isRecording = Variable(false)
let isPlaying = Variable(false)
let observable = Observable.combineLatest(isRecording.asObservable(), isPlaying.asObservable()) { (val1, val2) -> Void in
//...
However, to answer your question as to why it doesn't work with rx_observe
, it's because rx_observe
relies on the property being KVO compliant. If you used the dynamic
keyword in front of your property definitions, it would have worked: dynamic var isRecording = false
. However, you should really be using a Subject
such as Variable
. Check out the playground page dealing with Subject
s in the RxSwift
repo. It gives an example of each type.
Solution 2
With latest RxSwift 5.0+ you can use BehaviorRelay
let isLoading = BehaviorRelay<Bool>(value: false)
And you can observe it's value as below:
isLoading.asObservable().subscribe { status in
print(status)
}.disposed(by: disposeBag)
Marina
IOS developer with 7 years experience. Currently working on VOIP IOS application.
Updated on June 16, 2022Comments
-
Marina almost 2 years
I have two Bool properties in my VC.swift:
var isRecording = false var isPlaying = false
In the viewDidLoad() method I have such code:
let observable = Observable.combineLatest(self.rx_observe(Bool.self, "isRecording"), self.rx_observe(Bool.self, "isPlaying")) { (val1, val2) -> Void in if(val1 == false && val2 == false){ self.recordButton.enabled = true self.playButton.enabled = true self.recordButton.setImage(UIImage(named: "record"), forState: UIControlState.Normal) self.playButton.setImage(UIImage(named: "play"), forState: UIControlState.Normal) } else if(val1 == true && val2 == false){ self.recordButton.enabled = true self.recordButton.setImage(UIImage(named: "stop"), forState: UIControlState.Normal) self.playButton.enabled = false } else if(val1 == false && val2 == true){ self.recordButton.enabled = false self.playButton.enabled = true self.playButton.setImage(UIImage(named: "stop"), forState: UIControlState.Normal) self.recordButton.setImage(UIImage(named: "record"), forState: UIControlState.Normal) } }.observeOn(MainScheduler.instance) addSubscription(observable.subscribe())
The function addSubscription(:_) adds subscription to DisposableBag. The problem is that the code in the closure works only once. It does not work when properties "isRecording" and "isPlaying" change. What should I do if I want this code to be performed after I have these bool properties changed?
-
Marina almost 8 yearsThank u very much. It works. But I used this: let observable = Observable.combineLatest(isRecording.asObservable(), isPlaying.asObservable()) { (val1, val2) -> Void in //...
-
solidcell almost 8 yearsAh thanks for the catch. I've updated the answer. I also added an explanation as to why it wasn't working for you before.