[英]iOS RxSwift how to prevent sequence from being disposed on (throw error)?
我有一個由多個運算符組成的序列。 在此序列處理過程中,總共有7個地方可能會產生錯誤。 我遇到了一個問題,即該序列的行為不符合我的預期,我正在尋找一種解決該問題的優雅方法:
let inputRelay = PublishRelay<Int>()
let outputRelay = PublishRelay<Result<Int>>()
inputRelay
.map{ /*may throw multiple errors*/}
.flatmap{ /*may throw error*/ }
.map{}
.filter{}
.map{ _ -> Result<Int> in ...}
.catchError{}
.bind(to: outputRelay)
我以為catchError
會捕獲錯誤,讓我將其轉換為失敗結果,但防止序列被釋放。 但是,我看到第一次發現錯誤時,將重新分配整個序列,並且不再發生任何事件。
如果沒有這種行為,我到處都會看到一個笨拙的Results <>,並且不得不多次分支我的序列以將Result.failure(Error)
到輸出。 存在不可恢復的錯誤,因此retry(n)
不是一個選擇:
let firstOp = inputRelay
.map{ /*may throw multiple errors*/}
.share()
//--Handle first error results--
firstOp
.filter{/*errorResults only*/}
.bind(to: outputRelay)
let secondOp = firstOp
.flatmap{ /*may throw error*/ }
.share()
//--Handle second error results--
secondOp
.filter{/*errorResults only*/}
.bind(to: outputRelay)
secondOp
.map{}
.filter{}
.map{ _ -> Result<Int> in ...}
.catchError{}
.bind(to: outputRelay)
^這是非常糟糕的,因為大約有7個地方會引發錯誤,而我不能每次都保持分支的連續性。
RxSwift運算符如何捕獲所有錯誤並在最后發出失敗結果,但不將整個序列置於第一個錯誤上?
我想到的第一個技巧是使用materialize
。 這會將每個Observable<T>
轉換為Observable<Event<T>>
,因此Error只是.next(.error(Error))
,不會導致序列終止。
但是,在這種特定情況下,還需要另一個技巧。 把你的整個“觸發”鏈flatMap內,以及,並materialize
荷蘭國際集團的具體作品。 這是必需的,因為物化序列仍然可以完成,這會在規則鏈的情況下導致終止,但不會終止flatMapped鏈(因為flatMap內完成==成功完成)。
inputRelay
.flatMapLatest { val in
return Observable.just(val)
.map { value -> Int in
if value == 1 { throw SomeError.randomError }
return value + value
}
.flatMap { value in
return Observable<String>.just("hey\(value)")
}
.materialize()
}
.debug("k")
.subscribe()
inputRelay.accept(1)
inputRelay.accept(2)
inputRelay.accept(3)
inputRelay.accept(4)
這將為k
輸出以下內容:
k -> subscribed
k -> Event next(error(randomError))
k -> Event next(next(hey4))
k -> Event next(completed)
k -> Event next(next(hey6))
k -> Event next(completed)
k -> Event next(next(hey8))
k -> Event next(completed)
現在,您要做的就是僅過濾實例化序列中的“下一個”事件。
如果您具有RxSwiftExt ,則可以簡單地使用errors()
和elements()
運算符:
stream.elements()
.debug("elements")
.subscribe()
stream.errors()
.debug("errors")
.subscribe()
這將提供以下輸出:
errors -> Event next(randomError)
elements -> Event next(hey4)
elements -> Event next(hey6)
elements -> Event next(hey8)
使用此策略時,不要忘記在flatMap
之后添加share()
,因此許多訂閱不會引起多處處理。
您可以在此處了解有關為什么要在這種情況下使用共享的更多信息: http : //adamborek.com/how-to-handle-errors-in-rxswift/
希望這可以幫助!
是的,這很痛苦。 我考慮過創建一個新的庫的想法,該庫不需要語法以錯誤結束流,但是嘗試重現整個Rx生態系統似乎毫無意義。
有反應式庫,可讓您將Never
指定為錯誤類型(這意味着完全不會發出錯誤),在RxCocoa中,您可以使用Driver(不會發生錯誤),但是仍然留下整個結果舞蹈。 “我的Monad中的Monad!”。
為了正確處理它,您需要一組Monad變壓器 。 有了這些,您就可以完成所需的所有映射/平面映射,而不必擔心直到最后才看到錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.