RxSwift
来源:互联网 发布:修真的程序员txt下载 编辑:程序博客网 时间:2024/05/16 17:07
首先我们一起重新回顾一下,什么时候观察者序列会终止?
非常简单的几句话:无论什么时候观察者序列接收到错误(error)或者完成(completed)事件,观察者序列(Observables)将终止。终止意味着观察者序列的订阅者们将不再接收任何新的消息。
在开发中,我们经常碰到需要处理错误的情况,现在我们看一个真实的场景,比如:当用户点击按钮的时候,app经常需要进行一些API请求。如果我们请求操作使得观察者序列出现了非预期的终止,那么后续的点击操作将无效,点击按钮事件不再被发送。那么问题就变的麻烦起来了,接下来看看怎么处理这个情况,原文内容这里
功能描述:
现在我们来模拟当用户点击按钮的时候,app进行API请求。点击success按钮,将调用假的API请求,成功返回数据。同理,当点击failure按钮时,调用假的API请求,返回错误。并且每次操作按钮,记录成功和失败的次数。
UI布局:
具体实现代码:
let successesCount = Observable .of(successButton.rx.tap.map { true }, failureButton.rx.tap.map { false }) .merge() .flatMap { [unowned self] performWithSuccess in return self.performAPICall(shouldEndWithSuccess: performWithSuccess) }.scan(0) { accumulator, _ in return accumulator + 1 }.map { "\($0)" } successesCount.bindTo(successessCountLabel.rx.text) .disposed(by: disposeBag)
我们可以看到上面代码使用了of操作符创建了一个新的观察者序列,并且调用merge()合并successButton和failureButton两个按钮点击事件观察者序列,然后执行flatMap,进行API请求。每次请求,调用scan操作符记录操作的次数并调用map转换为字符串。下面是performAPICall
struct SampleError: Swift.Error {} private func performAPICall(shouldEndWithSuccess: Bool) -> Observable<Void> { if shouldEndWithSuccess { return .just(()) } else { return .error(SampleError()) } }
我们可能会想,上面的代码很简单啊。那么结果如何呢?下面看一下具体操作,当点击successButton,的确增加了成功的次数,但是,只要我们点击failureButton,整个观察者序列将被终止并dispose掉。而且再次点击successButton无效。并不会看到有任何改变,如下所示:
那么为什么会这样呢?其实在最开始,我们就一起回顾了观察者序列终止的情况:无论什么时候观察者序列接收到错误(error)或者完成(completed)事件,观察者序列(Observables)将终止。终止意味着观察者序列的订阅者们将不再接收任何新的消息。所以,如果一旦点击了failureButton,那么调用performAPICall方法的时候,会发送错误事件,那么观察者序列接收到了错误事件,自然而然就终止了。
但是实际情况是,即使接收了错误的情况,但是我们并不想终止后续的操作。所以我们可能想API调用返回的结果应该是Observable<Result<T>>,使用Result<T>做为下一个事件,这样就不会终止观察者序列了。这里有一个简单的方式处理,一个第三方库RxSwiftExt通过了materialize操作符。该操作符会返回一个观察者序列包含对应的事件,即转换Observable<T>到Observable<Event<T>>如下:
/** Convert any Observable into an Observable of its events. - seealso: [materialize operator on reactivex.io](http://reactivex.io/documentation/operators/materialize-dematerialize.html) - returns: An observable sequence that wraps events in an Event<E>. The returned Observable never errors, but it does complete after observing all of the events of the underlying Observable. */ public func materialize() -> RxSwift.Observable<RxSwift.Event<Self.E>>而Event就是RxSwift的Event枚举
/// Represents a sequence event.////// Sequence grammar: /// **next\* (error | completed)**public enum Event<Element> { /// Next element is produced. case next(Element) /// Sequence terminated with an error. case error(Swift.Error) /// Sequence completed successfully. case completed}并且有两个额外的操作符号,能够获取对应事件的数据
/// Return only the error events of an Observable<Event<E>> public func errors() -> RxSwift.Observable<Error> /// Return only the onNext element events of an Observable<Event<E>> public func elements() -> RxSwift.Observable<Self.E.E>由于上述功能,现在我们可能很好的处理之前的问题了,实现如下:
private func usingMaterialize() { let result = Observable .of(successButton.rx.tap.map { true }, failureButton.rx.tap.map { false }) .merge() .flatMap { [unowned self] performWithSuccess in return self.performAPICall(shouldEndWithSuccess: performWithSuccess) .materialize() }.share() result.elements() .scan(0) { accumulator, _ in return accumulator + 1 }.map { "\($0)" } .bindTo(successessCountLabel.rx.text) .disposed(by: disposeBag) result.errors() .scan(0) { accumulator, _ in return accumulator + 1 }.map { "\($0)" } .bindTo(failuresCountLabel.rx.text) .disposed(by: disposeBag) }注意:上面代码我们不仅使用了materialize而且使用了share(),保证共享同一观察者序列,避免每次有新的订阅执行不必要的API调用操作。具体原因可以看这里。之后我们就能够正常操作了。如下:
上面就是处理异常错误的方式。
推荐:
What is the correct way to handle errors
阅读全文
0 0
- RxSwift
- RxSwift
- RxSwift
- RxSwift
- RxSwift
- RxSwift
- RxSwift
- RxSwift
- RxSwift(一)
- RxSwift - API
- RxSwift - Why
- 什么是RxSwift?
- RxSwift学习心得
- RxSwift 教程 学习
- RxSwift使用教程
- iOS MVVM 与 RxSwift
- ReactiveCocoa和RXSwift速查表
- RxSwift 学习指导索引
- Mysql导出表结构及表数据 mysqldump用法
- python 常见bug解决方案记录
- Gstreamer源码安装(更新安装,基于ubuntu)
- [poj2406]Power Strings KMP
- Web移动端Fixed布局的解决方案
- RxSwift
- bzoj4926 皮皮妖的递推
- Spring中PropertyPlaceholderConfigurer类载入外部配置
- Redis和Memcache对比及选择
- shell 学习
- MYSQL:ERROR: Field '***' doesn't have a default value
- Spring任务调度<task:scheduled-tasks>【含cron参数详解】
- 通过旋转候选框实现任意方向的场景文本检测
- Deep learning系列(七)激活函数