簡體   English   中英

iOS RxSwift如何防止序列被處置(拋出錯誤)?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM