5

Observable.combineLatest(...){...} contains several observables, but some of these observables were not emitted.

combineLatest emits only when all observables in this method were emitted.

How to skip not emitted observables and emit combineLatest?

let tap = firstButton.rx.tap.asObservable().map{ (_) -> Observable<Item> ...}

let textfieldObservable = viewTextField.rx.text.orEmpty.asObservable()

submitButton.rx.tap.withLatestFrom(Observable.combineLatest(textfieldObservable, tap ... )).flatMapLatest({
...
// this method will not be executed without tap on firstButton before tapping on submitButton

}
)
Igor Kasuan
  • 792
  • 2
  • 10
  • 25

1 Answers1

24

combineLatest uses a closure that takes in as many arguments as it combines observables. So it makes sense it will wait for all the observables it combines to provide a value before it calls its closure.

But if you can find a sain default values for each of the observables provided to combineLatest, you could use startWith(_:) to force them into having an initial value.

This is what the code would look like using nil for item and the empty string for text

let tapObservable: Observable<Item> = // ...
let textField: Observable<String> = // ...

let combined = Observable.combineLatest(
  tapObservable.map { /* map everything to optional */ Optional.some($0) }.startWith(nil), 
  textField.startWith("")
) { item, text in
  // combine item and text
}

submitButton.rx.tap.withLatestFrom(combined)
tomahh
  • 13,441
  • 3
  • 49
  • 70
  • In my case, I had used `share()` on the input observables without specifying a value for `replay`. Setting this to `1` made it behave as desired. – alex bird Mar 21 '23 at 15:11