Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxSwift: Mapping a completable to single observable?

Tags:

ios

rx-swift

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?

like image 315
Yasir Avatar asked May 28 '17 18:05

Yasir


People also ask

What is RxSwift observable?

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.

What is onNext in RxSwift?

parameter onNext: Action to invoke for each element in the observable sequence. - returns: Subscription object used to unsubscribe from the observable sequence.

What is Completable RxSwift?

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.

How do you use single in RxSwift?

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.


2 Answers

I am not sure about RxSwift, but in RxJava you could to the following

repository.replace(with: value).andThen(Single.just(value))
like image 155
Wicket Avatar answered Sep 19 '22 06:09

Wicket


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))
}

Origional Answer Follows:

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>.

like image 26
Daniel T. Avatar answered Sep 21 '22 06:09

Daniel T.