ios - iOS RxSwift 如何防止序列被处理(抛出错误)?
问题描述
我有一个由多个运算符组成的序列。在这个序列处理过程中,总共有 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
. 这会将 every 转换Observable<T>
为Observable<Event<T>>
,因此 Error 只是 a.next(.error(Error))
并且不会导致序列终止。
但是,在这种特定情况下,将需要另一个技巧。将你的整个“触发”链也放在一个 flatMap 中,并materialize
ing 那个特定的部分。这是必需的,因为物化序列仍然可以完成,这会在常规链的情况下导致终止,但不会终止 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()
andelements()
运算符:
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)
使用此策略时,不要忘记share()
在 your 之后添加flatMap
,如此多的订阅不会导致多块处理。
你可以在这里阅读更多关于为什么你应该在这种情况下使用共享的信息:http: //adamborek.com/how-to-handle-errors-in-rxswift/
希望这可以帮助!
推荐阅读
- android - 如何使用浮动操作栏中心实现底部导航
- c# - 如何使用实体框架从数据库中的前 xxx 行搜索
- aws-lambda - 如何将上传/应用程序安装到设备场远程会话中
- cordova - Youtube API 在 Phonegap 中被阻止
- python - 通过对相同键的值求和来合并字典列表
- c++ - 如何有条件地实例化具有多个模板参数的模板类?
- reactjs - 渲染到带有上下文的字符串?
- java - 我在以下程序中得到 OptionalDataException。为什么会出现这个错误
- android - 如何处理 UI 中的数据库事务延迟以提供良好的用户体验?
- c++ - 将自定义对象添加到向量时如何启用移动语义?