swiftrx-swiftrx-cocoa

Why calling Completable method inside of flatMap does not working?


protocol TodoUseCase {
    func add(title: String, description: String) -> Completable
}


final class CreateTodoPresenterImpl: CreateTodoPresenter {
   var todoUseCase: TodoUseCase!
   var bag = DisposeBag()

   func setBind() {
        requestCreateTodoRelay
            .flatMap { [weak self] _ -> Completable in
                guard let weakSelf = self else { return Completable.empty() }
                return weakSelf.todoUseCase.add(title: weakSelf.titleInputtedText.value, description: weakSelf.descriptionInputtedText.value)
                .debug() // debug#1
            }
            .debug() // debug#2
            .subscribe(onError: { [weak self] error in
                self?._showAPIErrorPopupRelay.accept(error)
            }, onCompleted: { [weak self] in
                self?.toLoginView() 
            })
            .disposed(by: bag)
   }
}

Why this function todoUseCase.add() -> Completable, but does return nothing.

I want that when this todoUseCase.add called, call subscribe's onCompleted closure.

I tried to investigate this

I have a question, calling the returning Completable method inside of the flatMap method is wrong?


Solution

  • A flatMap does not complete until all subscribed Observables complete. In this case, that means that requestCreateTodoRelay and every Observable created by the closure would all have to complete before the flatMap emitted a completed event.

    It makes sense when you consider that once the Observable returned from flatMap emits a complete, it's not allowed to emit any other events. So it wouldn't be able to react properly when requestCreateTodoRelay emitted another next event.

    The solution is to have .add(title:description:) return a Single<Void> (or an Observable<Void> that emits both a next event and a completed event.

    This is a general rule by the way. If an observable is responding to multiple upstream observables, it will emit an error if any one upstream observable emits and error, but won't emit a completed event unless all upstream observables do so.