I am trying to do a couple of actions in sequence, using RxSwift and am unsure how to get it working.
The problem is returning a Single
observable, where the success/error depends on whether a Completable
call succeeds or fails.
My code attempt looks roughly like this:
func doSomething(with value: SomeType) -> Single<SomeType> {
return repository.replace(with: value) // replace() returns a completable
.asObservable()
.flatMap { () -> Single<SomeType> in
return Single.just(value)
}
}
Error on line 4 (flatMap):
Cannot convert call result type 'Observable<_.E>' to expected type 'PrimitiveSequence< SingleTrait, SomeType >' (aka 'PrimitiveSequence< SingleTrait, SomeType >')
How can I map this completable to a single?
The heart of the RxSwift framework is based on observable which is also known as a sequence. Observable is the sequence of data or events which can be subscribed and can be extended by applying different Rx operators like map, filter, flatMap, etc. It can receive data asynchronously.
parameter onNext: Action to invoke for each element in the observable sequence. - returns: Subscription object used to unsubscribe from the observable sequence.
A Completable is a variation of Observable that can only complete or emit an error. It is guaranteed to not emit any elements. Emits zero elements. Emits a completion event, or an error. Doesn't share side effects.
Common usage of Single :A Single can be used to model any case where you only care for a single element, and not for an infinite stream of elements. Once image is loaded, then you want to perform some operation.
I am not sure about RxSwift, but in RxJava you could to the following
repository.replace(with: value).andThen(Single.just(value))
Just a few months after I answered this question, a new operator was added to the Completable type. .andThen
. Using it makes this code much simpler:
func doSomething(with value: SomeType) -> Single<SomeType> {
return repository.replace(with: value)
.andThen(Single.just(value))
}
Hmm... A Completable never emits an element so there is nothing to flatMap to. I.E. it doesn't make sense to even use the flatMap
operator on a Completable. The only thing you can really do with it is subscribe to it.
Therefore, you need to implement your method like this:
func doSomething(with value: SomeType) -> Single<SomeType> {
return Single<SomeType>.create { observer in
return repository.replace(with: value)
.subscribe(onCompleted: {
observer(.success(value))
}, onError: {
observer(.error($0))
})
}
}
I've tried to work with Observables that don't emit values in the past, before these newfangled types, and I've always found them to be a pain. If I were you, I would convert your replace
method to return a Single<Void>
instead of a Completable
. i.e.:
func replace(with value: SomeType) -> Single<Void>
If you do that, then you can simply:
func doSomething(with value: SomeType) -> Single<SomeType> {
return repository.replace(with: value).map { value }
}
Of course if you can do that, then you might as well have replace(with:)
itself return a Single<SomeType>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With