前言
我们知道一个可被观察序列在它们收到error
或者completed
事件的时候会终止,终止也就意味着它的订阅者不会收到任何新的消息了。当我们开始学习Rx
的时候可能还不会意识到这条规则的后果。
example
很多的应用通常会在点击某个按钮的时候发网络请求,下面来看看这个例子。
点击Success
模拟调用一个api请求,返回成功,同样,点击Failure
触发error
,点击会增加计数。
code
首先把成功的点击返回true
,失败的点击返回false
,然后合并成单个序列。
1 | let successCount = Observable |
当点击Success
的时候会增加成功次数,但是当你点击Failure
的时候,整个可被观察序列会被释放,之后不管你怎么点Success
都不会再增加成功次数。
当performAPICall
返回了一个错误的事件的时候,其实和你在发送网络请求的时候也会出现。所以使用flatMap
也会把内部的next
和error
事件传到主序列。
结果,主序列收到error
事件,就终结了。。。
如何处理?
上面的情况假如Success
按钮是登录按钮,那么在错误后就不能点击了,这不是我们想要的。
这里我们可以借助Result
来传递错误信息。
其实在上一篇Moya
里面很多地方都有使用到Result
来传递错误。
创建一个Result
:
1 | enum Result<T>{ |
修改performAPICall
返回Result
:
1 | private func performAPICall2(shouldEndWithSuccess: Bool) -> Observable<Result<Void>> { |
然后分别处理成功和失败的情况:
1 | successCount |
这里增加了filterValue
和filterError
来获取我们想要的值。
如果不关心原来的错误,只处理成功,也可以增加如下方法:
1 | func map<T>(transform: (Value) throws -> T) -> Result<T> { |
错误接着往下传,执行逻辑,成功返回,发生错误传递错误。
使用RxSwiftExt
除了上面的方式,也可以使用RxSwiftExt
提供的materialize
操作。
它会把Observable<T>
intoObservable<Event<T>>
, 通过下面两个方法分别获取值和错误:
- elements() which returns Observable
- errors() which returns Observable
1 | let result = Observable |
和上次一样的把元素和错误一起包裹了一下,往下传递。
本文相关代码: