2015-10-31 13 views
6

Sono ancora un principiante reattivo e sto cercando aiuto.Combinazione di due osservabili <Void> s

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 

} 

Quanto sopra è quello che penso io voglio ... Le funzioni iniziali doA() e doB() rete avvolgere le chiamate in modo che saranno entrambi emettono un segnale e quindi Complete (o Error senza emettere alcun Next eventi). Se doA() Completa ma errori doB(), voglio doIt() emettere .BFailed e quindi completare.

Sembra che dovrei usare zip o combineLatest ma non sono sicuro di sapere quale sequenza non è riuscita se lo faccio. Sono anche abbastanza sicuro che catchError sia parte della soluzione, ma non sono sicuro di dove metterlo.

-

Come io sto pensando, sto bene con le chiamate accadendo in sequenza. Che potrebbe essere anche meglio ...

IE:

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

Grazie per qualsiasi aiuto.

risposta

0

Mi scuso per il fatto che non conosco la sintassi per swift, quindi sto scrivendo la risposta in C#. Il codice dovrebbe essere direttamente traducibile.

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

Fondamentalmente l'operatore .Materialize() trasforma il OnNext, OnError e OnCompleted notifiche per un'osservabile di tipo T in OnNext notifiche per un'osservabile di tipo Notification<T>. È quindi possibile impostare .Zip(...) e verificare le condizioni richieste.

+0

Hmm ... Grazie per la risposta, ma RxSwift non ha il metodo materialize. Almeno non ancora. –

0

Mi sembra di aver trovato una risposta da solo ... Ammetto che questa soluzione non attende il messaggio completo da doA() o doB(). Invece emette l'oggetto Result sul segnale onNext, ma poiché si tratta di chiamate di rete, ci sarà comunque solo un onNext prima del completamento. Forse pensare di dover aspettare il completamento è stata la cosa che mi rendeva difficile capire.

func doIt() -> Observable<Result> { 
    return doA().flatMap { 
     return doB().map { 
      .Success 
     } 
     .catchError { 
      just(.BFailed) 
     } 
    } 
} 
1

Credo .flatMapLatest() è quello che stai cercando, il concatenamento vostre richieste osservabili.

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) 

Ed ecco .flatMapLatest() doc in RxSwift.

Proietta ogni elemento di una sequenza osservabile in una nuova sequenza di sequenze osservabili e quindi trasforma una sequenza di sequenze osservabile osservabili in un'osservabile valori di sequenza produrre solo dal più recente sequenza osservabile. È una combinazione dell'operatore map + switchLatest.