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
debug#1 return onCompleted
debug#2 return nothing
I have a question, calling the returning Completable method inside of the flatMap method is wrong?
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.