10

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?

Yasir
  • 2,312
  • 4
  • 23
  • 35

2 Answers2

19

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

repository.replace(with: value).andThen(Single.just(value))
Wicket
  • 393
  • 3
  • 8
18

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

Daniel T.
  • 32,821
  • 6
  • 50
  • 72
  • Thanks, I figured as much and implemented it the same as you suggested. I will give Completable a few more chances, then make an assessment . – Yasir May 28 '17 at 23:40