2015-11-11 19 views
3

ReactiveCocoa 4對SignalProducer類,then,對於生產者等待完成,並與另一種生產像這樣替換它的方法:RAC 4夫特失敗方法

someProducer.then(replacementProducer)

然而,我想要的是一種方法,等到原始生產者錯誤出來,然後用第二個生產者(完成事件無所事事)替換它。

then實現爲(注意旁邊的事件不被轉發):

public func then<U>(replacement: SignalProducer<U, Error>) -> SignalProducer<U, Error> { 
    let relay = SignalProducer<U, Error> { observer, observerDisposable in 
     self.startWithSignal { signal, signalDisposable in 
      observerDisposable.addDisposable(signalDisposable) 

      signal.observe { event in 
       switch event { 
       case let .Failed(error): 
        observer.sendFailed(error) 
       case .Completed: 
        observer.sendCompleted() 
       case .Interrupted: 
        observer.sendInterrupted() 
       case .Next: 
        break 
       } 
      } 
     } 
    } 
    return relay.concat(replacement) 
} 

我想會看的,而不是發送一個錯誤,除了失敗相似,它會發出完成信號。更具體地說,switch語句會改變看起來像:

signal.observe { event in 
    switch event { 
     case .Failed: 
      observer.sendCompleted() 
     case .Completed, .Next: break 
     case .Interrupted: 
      observer.sendInterrupted() 
     } 
    } 
} 

我的問題如下:

1)這是有效的?它的工作方式與我所預期的一樣,只有當第一個信號出錯時纔會啓動替換信號。 2)有沒有更好的方法來做到這一點,使錯誤信息不會丟失?

的,我會用這樣的一個例子是一個兩步驗證過程:

self.verifyToken(token).failed(self.revalidateSession())

如果令牌驗證成功,一切都很好,沒有必要重新驗證。如果失敗,則需要重新驗證。

編輯:

我改變了信號觀察塊以使得如果所述第一信號與沒有錯誤完成時,它與startWithComplete以便完成事件被轉發向下鏈不脫離信號觸發任何動作開始替換信號。

這使得它很容易做到這一點:

self.verify(token).failed(self.refreshSession(token)).then(self.fetchUserForToken(token))

其中then被鏈接,只有當任一verifyrefreshSession成功得到執行。

signal.observe { event in 
    switch event { 
     case .Failed: 
      observer.sendCompleted() 
     case .Completed: 
      replacement.startWithCompleted {} 
     case .Next: break 
     case .Interrupted: 
      observer.sendInterrupted() 
     } 
    } 
} 

回答

1

1)這有效嗎?

號如果您的驗證信號發生器發送正常值並完成,您的更換信號製作者開始(由startWithCompleted通話),但會產生什麼(因爲你沒有遵守在startWithCompleted關閉任何東西,和內replay信號發生器永遠不會終止)。

2)有沒有更好的方法?

你可以使用flatMapError運算符,這樣你也可以得到錯誤信息。

self.verify(token) 
    .map { _ in() } 
    .flatMapError { error in 
     return self.refreshSession(token).map { _ in() } 
    } 

注意,這兩個map { _ in() }可以省略,如果相同類型的veriy生產者和refreshSession生產者產生的值。

+0

那麼我可以簡單地使用'map'和'flatMapError'來重寫我的'failed'方法嗎? – barndog

+0

取決於您是否想要觀察原始信號生成器的成功信號 – Cosyn