Rxswift: flatMap to Completable does not execute subscribe block

Created on 18 Apr 2019  路  7Comments  路  Source: ReactiveX/RxSwift

Short description of the issue:

When flatmapping to Completable, the subscribe block is not called, but the subscription is triggered.

Expected outcome:

Subscribe block is called.

Self contained code example that reproduces the issue:

    self.doneButton.rx.tap
        .flatMap {
          // doing an API call
          // returns Completable
          model.update().do(onCompleted: { log.debug("Completed") })  // api call is actually executed and the message is logged
        }
        .subscribe(onCompleted: {
          log.debug("Sub completed") // never called
          self.unwind() // this never called
        })
        .disposed(by: self.disposeBag)

RxSwift/RxCocoa/RxBlocking/RxTest version/commit

4.5.0

Platform/Environment

  • [x] iOS
  • [ ] macOS
  • [ ] tvOS
  • [ ] watchOS
  • [ ] playgrounds

How easy is to reproduce? (chances of successful reproduce after running the self contained code)

  • [x] easy, 100% repro
  • [ ] sometimes, 10%-100%
  • [ ] hard, 2% - 10%
  • [ ] extremely hard, %0 - 2%

Xcode version:
Xcode 10.2

Installation method:

  • [x] CocoaPods
  • [ ] Carthage
  • [ ] Git submodules

I have multiple versions of Xcode installed:
(so we can know if this is a potential cause of your issue)

  • [ ] yes (which ones)
  • [x] no

Level of RxSwift knowledge:
(this is so we can understand your level of knowledge
and formulate the response in an appropriate manner)

  • [ ] just starting
  • [x] I have a small code base
  • [ ] I have a significant code base

Most helpful comment

Yeah - think about it, if a flatMap completion would terminate the outer stream, it would mean that no more button taps would be registered in your stream, which don't really make sense.

As I mentioned, this is planned behavior. My example above worked because the "just" stream itself terminated immediatley.

All 7 comments

Completion inside a flatMap doesn鈥檛 complete the outer sequence.

@freak4pc So this is by design then? It's super-unobvious to me. I have some API calls that I don't care to get the result data for and they are all Completable. But I certainly would want to have outer sequence react to "completed" events... Just like in my example - a user presses a button, we make a call and then just close the page after the call is completed.

This actually works just fine for me

func c() -> Completable {
    return Completable.create { c in
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            c(.completed)
        }

        return Disposables.create()
    }
}

_ = Observable
    .just(())
    .flatMapLatest { c() }
    .subscribe(onCompleted: { print("yo") })

@freak4pc Tried your example directly in my codebase - worked. Replaced only the Observable part - to button.rx.tap - stopped working. But the same tap even works fine when flat mapping Single.

Yeah - think about it, if a flatMap completion would terminate the outer stream, it would mean that no more button taps would be registered in your stream, which don't really make sense.

As I mentioned, this is planned behavior. My example above worked because the "just" stream itself terminated immediatley.

Thanks for the explanation, I understood what you meant. Still, in my case, termination of tap evens would make sense and was exactly what I wanted. The idea was exactly that - do something and leave the page, so I wouldn鈥檛 care for any tap evens after the completed in the inner sequence.

You can do a take(1) on the button tap in that case.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gekitz picture gekitz  路  3Comments

jeremiegirault picture jeremiegirault  路  3Comments

apoloa picture apoloa  路  3Comments

RobinFalko picture RobinFalko  路  3Comments

marlowcharite picture marlowcharite  路  3Comments