Observable<Bool> If else in RxSwift - swift

I made Observable of Bool type as below
let allValid: Observable<Bool>
//All valid is combination of two more Observable<Bool>
allValid = Observable.combineLatest(checkBoxValid, reasonValid) { $0 && $1 }
Now I want to check when Done button is pressed, call respective method based on value of AllValid.
public func doneButtonPressed() {
//Here I have two methods, and to be called, when AllValid is true and false
//self.method1()
//self.method2()
}
Now how to make it. I cannot bind directly as it will trigger, and I want to trigger when Done is pressed.

The Rx way to do this would be to put this in your viewDidLoad
let isValid = doneButton.rx.tap.withLatestFrom(allValid)
isValid
.filter { $0 }
.subscribe(onNext: { _ in
// The button was tapped while the last value from allValid was true.
}
.disposed(by: bag)
isValid
.filter { !$0 }
.subscribe(onNext: { _ in
// The button was tapped while the last value from allValid was false.
}
.disposed(by: bag)

Related

How can i get controlEvent type in RxSwift?

I added textfield two controlEven with RxSwift I want to different things in a method.
textField.rx.controlEvent([.editingDidBegin, .editingDidEnd])
.asObservable()
.subscribe(onNext: { event in
// setFocusing(withType: ControlEvent)
})
private func setFocusing(type: ControlEvent) {
if type == .editingDidBegin {
//....
} else if type ==.editingDidEnd {
//....
}
}
I want to execute everything one method but how can I get controlEvent type? Is it possible?
Try this:
Observable.merge(
[.editingDidBegin, .editingDidEnd]
.map { event in
textField.rx.controlEvent(event).map { event }
}
)
.subscribe(onNext: setFocusing)
func setFocusing(type: UIControl.Event) {
if type == .editingDidBegin {
//....
} else if type == .editingDidEnd {
//....
}
}

Outlined consume of object crash in Combine receive func

Crashlytics states that there is a crash when updating the object var.The error is outlined consume of ObjectValue, from the add listeners func.
ObjectValue is a struct.
object is also updated from two other places. Is it possible that the updating in the combine call is unsafe (one places is accessing the memory while another place is changing its value)? How can I fix that?
var object: ObjectValue? = nil {
didSet {
guard oldValue != self.object else {
self.isLoading = false
return
}
self.prepareData()
}
}
override func addListeners() {
self.manager.objectValue.$value
.receive(on: RunLoop.main)
.sink { [weak self] objectValue in
guard self?.isDetailView == false else { return }
self?.object = objectValue
}
.store(in: &cancellables)
}

Return Type is not Optional, but asking to unwrap it

I have a method in ViewModel which is called registerSchool() and return is Bool. When I call this method in ViewController, then it says I need to unwrap it, because it is optional type. I did not mark the return type is optional! Why am I getting this error message?
ViewController -> RegisterViewController
var registerVM = RegisterVM()
#IBAction func registerBtnClicked(_ sender: Any) {
RegisterServiceManager.allUsers { [weak self] (result) in
guard let result = result else { return }
DispatchQueue.main.async {
// the following line saying the return is Bool?
if self?.registerVM.registerSchool() {
}
}
}
}
ViewModel -> RegisterVM
func registerSchool() -> Bool {
return true
}
Optional chaining. If self is Optional, self?.registerVM.registerSchool() is Optional.

Wait multiple observable requests to finish using RXSwift

I have a list of observables that are requests for google distance and duration info from an specific point. I'm trying to load my screen only when all this information is fetched, but my subscribe on next for those observables are never called (the line "observer.onNext(viewModel)" is called and has the information already fetched, only the subscribe(onNext) is not being called). How can I wait til those observables complete?
func stationInfoObservable(userLocation: CLLocationCoordinate2D, stations: [Station]) -> [Observable<GasStationTableCellViewModel>] {
var observables: [Observable<GasStationTableCellViewModel>] = []
for station in stations {
observables.append(Observable.create({ observer in
guard let toCoordinate = station.coordinate() else { return Disposables.create() }
self.mapDirections.routes(from: userLocation.asPlace(), to: toCoordinate.asPlace()) { routes, error in
if let error = error {
logger.error(error)
} else {
guard let leg = routes.first?.legs?.first else {
return
}
guard let distance = leg.distance?.text, let duration = leg.duration?.text else { return }
station.distanceInKMFromUserLocation = distance
station.distanceInMinutesFromUserLocation = duration
let viewModel = GasStationTableCellViewModel(station: station)
observer.onNext(viewModel)
observer.onCompleted()
}
}
return Disposables.create()
}))
}
return observables
}
I'm trying to subscribe this way (EDIT: I'm now trying to use zip, but the the drive / subscribe continues not being called):
Observable.zip(observables)
.asDriver(onErrorJustReturn: [])
.drive(onNext: { test in
print(test)
}, onCompleted: {
print("aa")
}).disposed(by: DisposeBag())
Based on your subscription code, it looks like you're not retaining the DisposeBag. You must retain this object because when it gets deallocated, all disposables it owns get immediately disposed. Try making it a property and use the property:
class MyClass {
let disposeBag = DisposeBag()
func setupSubscription() {
Observable.zip(observables)
.asDriver(onErrorJustReturn: [])
.drive(onNext: { test in
print(test)
}, onCompleted: {
print("aa")
}).disposed(by: disposeBag)
}
}

Understanding RxSwift Observable Chain

This is my a simplified version of my code:
var myObservable: Observable<MyEnum>
var modelObservable: Observable<Model?>
myObservable = myButton.rx.tap.asSignal()
.asObservable()
.flatMapLatest {
getModel()
}.map { model in
print("this is called")
return model.prop == true ? MyEnum.first : MyEnum.second
}
func getModel() -> Observable<Model?> {
if let model = self.model.value {
return Observable.just(model)
}
createModel()
return modelObservable
}
myObservable.subscribe(onNext: { (enum) in
switch enum {
case .first:
self.presentFirst()
case .second:
self.presentSecond()
}
}).disposed(by: bag)
I was expecting this code to mean that whenever myButton is tapped, this code would run and print "this is called", however, "this is called" is printed also when myOtherObservable is triggered, even when myButton is not tapped. Why does this happen? This makes me think I don't understand Rx. Also, how would I make it behave so that it only runs when the myButton is tapped?