Объединение двух Observable‹Void›

Я все еще реактивный новичок, и я ищу помощи.

func doA() -> Observable<Void>
func doB() -> Observable<Void>

enum Result {
    case Success
    case BFailed
}

func doIt() -> Observable<Result> {

    // start both doA and doB. 
    // If both complete then emit .Success and complete
    // If doA completes, but doB errors emit .BFailed and complete
    // If both error then error

}

Вышеупомянутое - это то, что я думаю, что хочу... Начальные функции doA() и doB() оборачивают сетевые вызовы, поэтому они обе будут генерировать один сигнал, а затем Complete (или Error без генерации каких-либо событий Next). Если doA() завершается, но doB() ошибок, я хочу doIt() чтобы испустить .BFailed, а затем завершить.

Такое ощущение, что я должен использовать zip или combineLatest, но я не уверен, как узнать, какая последовательность не удалась, если я это сделаю. Я также почти уверен, что catchError является частью решения, но я не уверен, куда именно его поместить.

--

Пока я думаю об этом, я согласен с тем, что вызовы происходят последовательно. Может быть, это даже лучше...

IE:

Start doA() 
    if it completes start doB() 
        if it completes emit .Success 
        else emit .BFailed.
    else forward the error.

Спасибо за любую помощь.


person Daniel T.    schedule 31.10.2015    source источник


Ответы (3)


Я считаю, что .flatMapLatest() - это то, что вы ищете, связывая свои наблюдаемые запросы.

doFirst()
.flatMapLatest({ [weak self] (firstResult) -> Observable<Result> in
  // Assuming this doesn't fail and returns result on main scheduler,
  // otherwise `catchError` and `observeOn(MainScheduler.instance)` can be used to correct this
  // ...
  // do something with result #1
  // ...
  return self?.doSecond()
}).subscribeNext { [weak self] (secondResult) -> Void in
  // ...
  // do something with result #2
  // ...
}.addDisposableTo(disposeBag)

А вот и .flatMapLatest() документ в RxSwift.

Проецирует каждый элемент наблюдаемой последовательности в новую последовательность наблюдаемых последовательностей, а затем преобразует наблюдаемую последовательность наблюдаемых последовательностей в наблюдаемую последовательность, производя значения только из самой последней наблюдаемой последовательности. Это комбинация оператора map + switchLatest.

person Son Nguyen    schedule 19.03.2016

Прошу прощения, что не знаю синтаксиса для swift, поэтому пишу ответ на С#. Код должен быть непосредственно переводим.

var query =
    doA
        .Materialize()
        .Zip(doB.Materialize(), (ma, mb) => new { ma, mb })
        .Select(x =>
            x.ma.Kind == NotificationKind.OnError
            || x.mb.Kind == NotificationKind.OnError
                ? Result.BFailed
                : Result.Success);

По сути, оператор .Materialize() превращает уведомления OnNext, OnError и OnCompleted для наблюдаемого типа T в уведомления OnNext для наблюдаемого типа Notification<T>. Затем вы можете .Zip(...) выполнить их и проверить необходимые условия.

person Enigmativity    schedule 31.10.2015
comment
Хм... Спасибо за ответ, но в RxSwift нет метода материализации. По крайней мере, пока. - person Daniel T.; 01.11.2015

Кажется, я сам нашел ответ... По общему признанию, это решение не ждет полного сообщения ни от doA(), ни от doB(). Вместо этого он выдает объект Result в сигнале onNext, но поскольку это сетевые вызовы, в любом случае перед завершением будет только один onNext. Может быть, мысль о том, что я должен ждать завершения, мешала мне понять.

func doIt() -> Observable<Result> {
    return doA().flatMap {
        return doB().map { 
            .Success 
        }
        .catchError {
            just(.BFailed)
        }
    }
}
person Daniel T.    schedule 01.11.2015