1.RxSwift目的->简化异步编程框架
1.1 概念
“它拓展了观察者模式。使你能够自由组合多个异步事件,而不需要去关心线程,同步,线程安全,并发数据以及I/O阻塞。”
1.2主要具有哪些功能
1.2.1 实现点击按钮方法Target Action
button.rx.tap.subscribe(onNext: {print("button Tapped")}).disposed(by: disposeBag)button.rx.tap.bind { [weak self] _ -> Void inself?.openAppPreferences()}.disposed(by: disposeBag)
讯享网
1.2.2实现代理
讯享网scrollView.rx.contentOffset.subscribe(onNext: { contentOffset inprint("contentOffset: \(contentOffset)")}).disposed(by: disposeBag)
1.2.3.闭包回调
URLSession.shared.rx.data(request: URLRequest(url: url)).subscribe(onNext: { data inprint("Data Task Success with count: \(data.count)")}, onError: { error inprint("Data Task Error: \(error)")}).disposed(by: disposeBag)
1.2.4.通知
讯享网NotificationCenter.default.rx.notification(.UIApplicationWillEnterForeground).subscribe(onNext: { (notification) inprint("Application Will Enter Foreground")}).disposed(by: disposeBag) 不需要去管理观察者的生命周期,这样你就有更多精力去关注业务逻辑
1.2.5.KVO
user.rx.observe(String.self, #keyPath(User.name)).subscribe(onNext: { newValue inprint("do something with newValue")}).disposed(by: disposeBag) 这样实现 KVO 的代码更清晰,更简洁并且更准确。
1.2.6.多个任务之间有依赖关系
讯享网/// 用 Rx 封装接口 enum Api {/// 通过用户名密码取得一个 tokenstatic func token(username: String, password: String) -> Observable<String> { ... }/// 通过 token 取得用户信息static func userInfo(token: String) -> Observable<UserInfo> { ... } } /// 通过用户名和密码获取用户信息 Api.token(username: "beeth0ven", password: "").flatMapLatest(Api.userInfo).subscribe(onNext: { userInfo inprint("获取用户信息成功: \(userInfo)")}, onError: { error inprint("获取用户信息失败: \(error)")}).disposed(by: disposeBag) 你无需嵌套太多层,从而使得代码易读,易维护
1.2.7.等待多个并发任务完成后处理结果
// 需要将两个网络请求合并成一个, /// 用 Rx 封装接口 enum Api {/// 取得老师的详细信息static func teacher(teacherId: Int) -> Observable<Teacher> { ... }/// 取得老师的评论static func teacherComments(teacherId: Int) -> Observable<[Comment]> { ... } } /// 同时取得老师信息和老师评论 Observable.zip(Api.teacher(teacherId: teacherId),Api.teacherComments(teacherId: teacherId)).subscribe(onNext: { (teacher, comments) inprint("获取老师信息成功: \(teacher)")print("获取老师评论成功: \(comments.count) 条")}, onError: { error inprint("获取老师信息或评论失败: \(error)")}).disposed(by: disposeBag)
1.3 使用RxSwift的优势
理由:那么为什么要使用 RxSwift
- 复合 - Rx 就是复合的代名词
- 复用 - 因为它易复合
- 清晰 - 因为声明都是不可变更的
- 易用 - 因为它抽象的了异步编程,使我们统一了代码风格
- 稳定 - 因为 Rx 是完全通过单元测试的
1.4 RxSwift原理
函数式编程是种编程范式,它需要我们将函数作为参数传递,或者作为返回值返还。数据绑定(订阅)关系:
讯享网 数据绑定 可被监听的序列==========>观察者
核心内容
讯享网
- Observable - 产生事件,所有的事物都是序列,用于描述元素异步产生的序列。
- Observer - 响应事件
- Operator - 创建变化组合事件
- Disposable - 管理绑定(订阅)的生命周期
- Schedulers - 线程队列调配
1.4.1 产生事件
// Observable<String> let text = usernameOutlet.rx.text.orEmpty.asObservable() // Observable<Bool> let passwordValid = text// Operator.map { $0.characters.count >= minimalUsernameLength }
1.4.2 Observer —响应事件,观察者,具体实现
讯享网// Observer<Bool> let observer = passwordValidOutlet.rx.isHidden
1.4.3 取消绑定
// Disposable let disposable = passwordValid// Scheduler 用于控制任务在那个线程队列运行.subscribeOn(MainScheduler.instance).observeOn(MainScheduler.instance).bind(to: observer) // 取消绑定,你可以在退出页面时取消绑定 disposable.dispose()
2.如何创建事件(序列)
2.1最简单的创建
讯享网let numbers: Observable<Int> = Observable.create({ observer -> Disposable inobserver.onNext(1)// 产生了一个元素,他的值是 1observer.onNext(2)observer.onNext(3) observer.onCompleted() // 表示元素已经全部产生,没有更多元素了return Disposables.create()})
2.2 决策树
• 产生特定的一个元素:just • 经过一段延时:timer • 从一个序列拉取元素:from • 重复的产生某一个元素:repeatElement • 存在自定义逻辑:create • 每次订阅时产生:deferred • 每隔一段时间,发出一个元素:interval • 在一段延时后:timer • 一个空序列,只有一个完成事件:empty • 一个任何事件都没有产生的序列:never 我想要创建一个 Observable 通过组合其他的 Observables • 任意一个 Observable 产生了元素,就发出这个元素:merge • 让这些 Observables 一个接一个的发出元素,当上一个 Observable 元素发送完毕后,下一个Observable 才能开始发出元素:concat • 组合多个 Observables 的元素 • 当每一个 Observable 都发出一个新的元素:zip • 当任意一个 Observable 发出一个新的元素:combineLatest 我想要转换 Observable 的元素后,再将它们发出来 • 对每个元素直接转换:map • 转换到另一个 Observable:flatMap • 只接收最新的元素转换的 Observable 所产生的元素:flatMapLatest • 每一个元素转换的 Observable 按顺序产生元素:concatMap • 基于所有遍历过的元素: scan 我想要将产生的每一个元素,拖延一段时间后再发出:delay 我想要将产生的事件封装成元素发送出来 • 将他们封装成 Event<Element>:materialize • 然后解封出来:dematerialize 我想要忽略掉所有的 next 事件,只接收 completed 和 error 事件:ignoreElements 我想创建一个新的 Observable 在原有的序列前面加入一些元素:startWith 我想从 Observable 中收集元素,缓存这些元素之后在发出:buffer 我想将 Observable 拆分成多个 Observables:window • 基于元素的共同特征:groupBy 我想只接收 Observable 中特定的元素 • 发出唯一的元素:single 我想重新从 Observable 中发出某些元素 • 通过判定条件过滤出一些元素:filter • 仅仅发出头几个元素:take • 仅仅发出尾部的几个元素:takeLast • 仅仅发出第 n 个元素:elementAt • 跳过头几个元素 • 跳过头 n 个元素:skip • 跳过头几个满足判定的元素:skipWhile,skipWhileWithIndex • 跳过某段时间内产生的头几个元素:skip • 跳过头几个元素直到另一个 Observable 发出一个元素:skipUntil • 只取头几个元素 • 只取头几个满足判定的元素:takeWhile,takeWhileWithIndex • 只取某段时间内产生的头几个元素:take • 只取头几个元素直到另一个 Observable 发出一个元素:takeUntil • 周期性的对 Observable 抽样:sample • 发出那些元素,这些元素产生后的特定的时间内,没有新的元素产生:debounce • 直到元素的值发生变化,才发出新的元素:distinctUntilChanged • 并提供元素是否相等的判定函数:distinctUntilChanged • 在开始发出元素时,延时后进行订阅:delaySubscription 我想要从一些 Observables 中,只取第一个产生元素的 Observable:amb 我想评估 Observable 的全部元素 • 并且对每个元素应用聚合方法,待所有元素都应用聚合方法后,发出结果:reduce • 并且对每个元素应用聚合方法,每次应用聚合方法后,发出结果:scan 我想把 Observable 转换为其他的数据结构:as... 我想在某个 Scheduler 应用操作符:subscribeOn • 在某个 Scheduler 监听:observeOn 我想要 Observable 发生某个事件时, 采取某个行动:do 我想要 Observable 发出一个 error 事件:error • 如果规定时间内没有产生元素:timeout 我想要 Observable 发生错误时,优雅的恢复 • 如果规定时间内没有产生元素,就切换到备选 Observable :timeout • 如果产生错误,将错误替换成某个元素 :catchErrorJustReturn • 如果产生错误,就切换到备选 Observable :catchError • 如果产生错误,就重试 :retry 我创建一个 Disposable 资源,使它与 Observable 具有相同的寿命:using 我创建一个 Observable,直到我通知它可以产生元素后,才能产生元素:publish • 并且,就算是在产生元素后订阅,也要发出全部元素:replay • 并且,一旦所有观察者取消观察,他就被释放掉:refCount • 通知它可以产生元素了:connect
2.3 事件 onNext, onError, onCompleted 事件。我们称这些事件为 Event:
``` public enum Event {case next(Element)// 序列产生了一个新的元素case error(Swift.Error)// 创建序列时产生了一个错误,导致序列终止case completed // 序列的所有元素都已经成功产生,整个序列已经完成 } ```
2.4.特征序列
- Single // 它要么只能发出一个元素,要么产生一个 error 事件。例子: HTTP 请求,然后返回一个应答或错误
- Completable. // 只能产生一个 completed 事件,要么产生一个 error 事件; 不会共享状态变化
- Maybe. // 发出一个元素或者一个 completed 事件或者一个 error 事件;不会共享状态变化
- Driver // 不会产生 error 事件 ;一定在 MainScheduler 监听(主线程监听); 共享状态变化; asDriver(onErrorJustReturn: []) 转换drive 而不是 bindTo,drive 方法只能被 Driver 调用
- ControlEvent // 专门用于描述 UI 控件所产生的事件;不会产生 error 事件;一定在 MainScheduler 订阅;一定在 MainScheduler 监听; 共享状态变化
2.4.1 Sigle 事件枚举
讯享网public enum SingleEvent<Element> {case success(Element)// 产生一个单独的元素case error(Swift.Error) // 产生一个错误 }
创建办法
Single<[String: Any]>.create> 对 Observable 调用 .asSingle() 方法,将它转换为 Single
2.4.2 Completable
只关心任务是否完成,而不需要在意任务返回值的情况。它和 Observable 有点相似
2.5 Observer - 观察者. 用来监听事件,然后它需要这个事件做出响应, 响应事件的都是观察者
如:弹出提示框就是观察者,它对点击按钮这个事件做出响应。
2.5.1创建观察者
创建观察者最直接的方法就是在 Observable 的 subscribe 方法后面描述,事件发生时,需要如何做出响应。而观察者就是由后面的 onNext,onError,onCompleted的这些闭包构建出来的。
tap.subscribe(onNext: { [weak self] inself?.showAlert() }, onError: { error inprint("发生错误: \(error.localizedDescription)") }, onCompleted: {print("任务完成") })
2.5.1特殊观察者
AnyObserver 可以用来描叙任意一种观察者> Binder 有2个特征:不会处理错误事件;确保绑定都是在给定 Scheduler 上执行(默认 MainScheduler)
讯享网打印网络请求结果: URLSession.shared.rx.data(request: URLRequest(url: url)).subscribe(onNext: { data inprint("Data Task Success with count: \(data.count)")}, onError: { error inprint("Data Task Error: \(error)")}).disposed(by: disposeBag)可以看作是: let observer: AnyObserver<Data> = AnyObserver { (event) inswitch event {case .next(let data):print("Data Task Success with count: \(data.count)")case .error(let error):print("Data Task Error: \(error)")default:break} }
由于这个观察者是一个 UI 观察者,所以它在响应事件时,只会处理 next 事件,并且更新 UI 的操作需要在主线程上执行。 let observer: Binder<Bool> = Binder(usernameValidOutlet) { (view, isHidden) inview.isHidden = isHidden } usernameValid.bind(to: observer).disposed(by: disposeBag)
Binder 可以只处理 next 事件,并且保证响应 next 事件的代码一定会在给定 Scheduler 上执行,这里采用默认的 MainScheduler。
复用 页面是否隐藏是一个常用的观察者,所以应该让所有的 UIView 都提供这种观察者:
讯享网extension Reactive where Base: UIView {public var isHidden: Binder<Bool> {return Binder(self.base) { view, hidden inview.isHidden = hidden}} } usernameValid.bind(to: usernameValidOutlet.rx.isHidden).disposed(by: disposeBag)label 的当前文本 label.rx.text: extension Reactive where Base: UILabel {public var text: Binder<String?> {return Binder(self.base) { label, text inlabel.text = text}} }
2.6 Observable & Observer 既是可被监听的序列也是观察者
// 作为可被监听的序列 let observable = textField.rx.text observable.subscribe(onNext: { text in show(text: text) }) // 作为观察者 let observer = textField.rx.text let text: Observable<String?> = ... text.bind(to: observer)
同样具有此特性的UI控件有:switch的开关状态,segmentedControl的选中索引号,datePicker的选中日期, UISlider, UIStepper等等 controlPropertyWithDefaultEvents
其他辅助类也具有可被监听的序列也是观察者的对象
讯享网> AsyncSubject // Observable 产生完成事件后,发出最后一个元素(仅仅只有最后一个元素) > PublishSubject > ReplaySubject > BehaviorSubject > Variable > ControlProperty
2.6.1 AsyncSubject
在源 Observable 产生完成事件后,发出最后一个元素(仅仅只有最后一个元素),如果源 Observable 没有发出任何元素,只有一个完成事件。那 AsyncSubject 也只有一个完成事件;如果源 Observable 因为产生了一个 error 事件而中止,
AsyncSubject 就不会发出任何元素,而是将这个 error 事件发送出来。
let disposeBag = DisposeBag() let subject = AsyncSubject<String>() subject.subscribe { print("Subscription: 1 Event:", $0) }.disposed(by: disposeBag) subject.onNext("🐶") subject.onNext("🐱") subject.onNext("🐹") subject.onCompleted() 输出结果: Subscription: 1 Event: next(🐹) Subscription: 1 Event: completed
2.6.2 ReplaySubject
PublishSubject 将对观察者发送订阅后产生的元素,而在订阅前发出的元素将不会发送给观察者。如果你希望观察者接收到所有的元素,你可以通过使用 Observable 的 create 方法来创建 Observable,或者使用 ReplaySubject。
如果源 Observable 因为产生了一个 error 事件而中止, PublishSubject 就不会发出任何元素,而是将这个 error 事件发送出来。
讯享网let disposeBag = DisposeBag() let subject = PublishSubject<String>() subject.subscribe { print("Subscription: 1 Event:", $0) }.disposed(by: disposeBag) subject.onNext("🐶") subject.onNext("🐱") subject.subscribe { print("Subscription: 2 Event:", $0) }.disposed(by: disposeBag) subject.onNext("🅰️") subject.onNext("🅱️") 输出结果: Subscription: 1 Event: next(🐶) Subscription: 1 Event: next(🐱) Subscription: 1 Event: next(🅰️) Subscription: 2 Event: next(🅰️) Subscription: 1 Event: next(🅱️) Subscription: 2 Event: next(🅱️)
2.6.3 ReplaySubject
ReplaySubject 将对观察者发送全部的元素,无论观察者是何时进行订阅的。
如果把 ReplaySubject 当作观察者来使用,注意不要在多个线程调用 onNext, onError 或 onCompleted。这样会导致无序调用,将造成意想不到的结果。
let disposeBag = DisposeBag() let subject = ReplaySubject<String>.create(bufferSize: 1) subject.subscribe { print("Subscription: 1 Event:", $0) }.disposed(by: disposeBag) subject.onNext("🐶") subject.onNext("🐱") subject.subscribe { print("Subscription: 2 Event:", $0) }.disposed(by: disposeBag) subject.onNext("🅰️") subject.onNext("🅱️") 输出结果: Subscription: 1 Event: next(🐶) Subscription: 1 Event: next(🐱) Subscription: 2 Event: next(🐱) Subscription: 1 Event: next(🅰️) Subscription: 2 Event: next(🅰️) Subscription: 1 Event: next(🅱️) Subscription: 2 Event: next(🅱️)
2.6.4 BehaviorSubject
当观察者对 BehaviorSubject 进行订阅时,它会将源 Observable 中最新的元素发送出来(如果不存在最新的元素,就发出默认元素)。然后将随后产生的元素发送出来。
如果源 Observable 因为产生了一个 error 事件而中止, BehaviorSubject 就不会发出任何元素,而是将这个 error 事件发送出来。
讯享网let disposeBag = DisposeBag() let subject = BehaviorSubject(value: "🔴") subject.subscribe { print("Subscription: 1 Event:", $0) }.disposed(by: disposeBag) subject.onNext("🐶") subject.onNext("🐱") subject.subscribe { print("Subscription: 2 Event:", $0) }.disposed(by: disposeBag) subject.onNext("🅰️") subject.onNext("🅱️") subject.subscribe { print("Subscription: 3 Event:", $0) }.disposed(by: disposeBag) subject.onNext("🍐") subject.onNext("🍊") 输出结果: Subscription: 1 Event: next(🔴) Subscription: 1 Event: next(🐶) Subscription: 1 Event: next(🐱) Subscription: 2 Event: next(🐱) Subscription: 1 Event: next(🅰️) Subscription: 2 Event: next(🅰️) Subscription: 1 Event: next(🅱️) Subscription: 2 Event: next(🅱️) Subscription: 3 Event: next(🅱️) Subscription: 1 Event: next(🍐) Subscription: 2 Event: next(🍐) Subscription: 3 Event: next(🍐) Subscription: 1 Event: next(🍊) Subscription: 2 Event: next(🍊) Subscription: 3 Event: next(🍊)
2.6.5 Variable
RxSwift 提供的 Variable,可变量的版本

使用 var:
// 在 ViewController 中 var model: Model? = nil {didSet { updateUI(with: model) } } override func viewDidLoad() {super.viewDidLoad()model = getModel() } func updateUI(with model: Model?) { ... } func getModel() -> Model { ... }
使用 Variable:
讯享网// 在 ViewController 中 let model: Variable<Model?> = Variable(nil) override func viewDidLoad() {super.viewDidLoad()model.asObservable().subscribe(onNext: { [weak self] model inself?.updateUI(with: model)}).disposed(by: disposeBag)model.value = getModel() } func updateUI(with model: Model?) { ... } func getModel() -> Model { ... }
第一种使用 var 的方式十分常见,在 ViewController 中监听 Model 的变化,然后刷新页面。
第二种使用 Variable 则是 RxSwift 独有的。Variable 几乎提供了 var 的所有功能。另外,加上一条非常重要的特性,就是可以通过调用 asObservable() 方法转换成序列。然后你可以对这个序列应用操作符,来合成其他的序列。所以,如果我们声明的变量需要提供 Rx 支持,那就选用 Variable 这个类型
说明 Variable 封装了一个 BehaviorSubject,所以它会持有当前值,并且 Variable 会对新的观察者发送当前值。它不会产生 error 事件。Variable 在 deinit 时,会发出一个 completed 事件
2.6.6 ControlProperty
ControlProperty 专门用于描述 UI 控件属性的,它具有以下特征:
- 不会产生 error 事件
- 一定在 MainScheduler 订阅(主线程订阅)
- 一定在 MainScheduler 监听(主线程监听)
- 共享状态变化
2.7操作符
操作符的目的:创建新的序列,或者变化组合原有的序列,从而生成一个新的序列. 操作符有以下:
2.7.1 filter - 过滤,这个序列只发出温度大于 33 度的元素
// 温度 let rxTemperature: Observable<Double> = ... // filter 操作符 rxTemperature.filter { temperature in temperature > 33 }.subscribe(onNext: { temperature inprint("高温:\(temperature)度")}).disposed(by: disposeBag)
2.7.2 map - 转换,创建一个新的序列。这个序列将原有的 JSON 转换成 Model 。这种转换实际上就是解析 JSON 。
讯享网// JSON let json: Observable<JSON> = ... // map 操作符 json.map(Model.init).subscribe(onNext: { model inprint("取得 Model: \(model)")}).disposed(by: disposeBag)
2.7.3 zip - 配对, 这个序列将汉堡序列的元素和薯条序列的元素配对后,生成一个新的套餐序列。
// 汉堡 let rxHamburg: Observable<Hamburg> = ... // 薯条 let rxFrenchFries: Observable<FrenchFries> = ... // zip 操作符 Observable.zip(rxHamburg, rxFrenchFries).subscribe(onNext: { (hamburg, frenchFries) inprint("取得汉堡: \(hamburg) 和薯条:\(frenchFries)")}).disposed(by: disposeBag)
其他操作符列表
讯享网amb buffer catchError combineLatest concat concatMap connect create debounce debug deferred delay delaySubscription dematerialize distinctUntilChanged do elementAt empty error filter flatMap flatMapLatest from groupBy ignoreElements interval just map merge materialize never observeOn publish reduce refCount repeatElement replay retry sample scan shareReplay single skip skipUntil skipWhile startWith subscribeOn take takeLast takeUntil takeWhile timeout timer using window withLatestFrom zip
2.8 Disposable - 可被清除的资源
1.主动取消订阅
var disposeBag = DisposeBag() textField.rx.text.orEmpty.subscribe(onNext: { text in print(text) }).disposed(by: self.disposeBag)
disposeBag 和 ViewController 具有相同的生命周期。当退出页面时, ViewController 就被释放,disposeBag 也跟着被释放了,那么这里的 5 次绑定(订阅)也就被取消了。这正是我们所需要的。
2.自动取消订阅
讯享网_ = usernameValid.takeUntil(self.rx.deallocated).bind(to: passwordOutlet.rx.isEnabled)
这将使得订阅一直持续到控制器的 dealloc 事件产生为止。
2.9 Schedulers - 调度器
Schedulers 是 Rx 实现多线程的核心模块,它主要用于控制任务在哪个线程或队列运行。
// 后台取得数据,主线程处理结果 DispatchQueue.global(qos: .userInitiated).async {let data = try? Data(contentsOf: url)DispatchQueue.main.async {self.data = data} }
如果用 RxSwift 来实现,大致是这样的:
讯享网let rxData: Observable<Data> = ... rxData.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)).observeOn(MainScheduler.instance).subscribe(onNext: { [weak self] data inself?.data = data}).disposed(by: disposeBag)
使用subscribeOn来决定数据序列的构建函数在哪个 Scheduler 上运行以上例子中,由于获取 Data 需要花很长的时间,所以用 subscribeOn 切换到 后台 Scheduler 来获取 Data。这样可以避免主线程被阻塞。使用 observeOn来决定在哪个 Scheduler 监听这个数据序列通过使用 observeOn 方法切换到主线程来监听并且处理结果。一个比较典型的例子就是,在后台发起网络请求,然后解析数据,最后在主线程刷新页面。你就可以先用 subscribeOn 切到后台去发送请求并解析数据,最后用 observeOn 切换到主线程更新页面。
- MainScheduler MainScheduler 代表主线程。如果你需要执行一些和 UI 相关的任务,就需要切换到该
Scheduler运行。* SerialDispatchQueueScheduler SerialDispatchQueueScheduler 抽象了串行DispatchQueue。如果你需要执行一些串行任务,可以切换到这个Scheduler运行。* ConcurrentDispatchQueueSchedulerConcurrentDispatchQueueScheduler抽象了并行DispatchQueue。如果你需要执行一些并发任务,可以切换到这个Scheduler运行。* OperationQueueScheduler OperationQueueScheduler 抽象了NSOperationQueue。 它具备 NSOperationQueue 的一些特点,例如,你可以通过设置maxConcurrentOperationCount,来控制同时执行并发任务的最大数量。 2.10 Error Handling - 错误处理
一旦序列里面产出了一个 error 事件,整个序列将被终止。RxSwift 主要有两种错误处理机制:
- retry - 重试
- catch - 恢复
retry 可以让序列在发生错误后重试:
// 请求 JSON 失败时,立即重试, // 重试 3 次后仍然失败,就将错误抛出 let rxJson: Observable<JSON> = ... rxJson.retry(3).subscribe(onNext: { json inprint("取得 JSON 成功: \(json)")}, onError: { error inprint("取得 JSON 失败: \(error)")}).disposed(by: disposeBag)
以上的代码非常直接 retry(3) 就是当发生错误时,就进行重试操作,并且最多重试 3 次。
retryWhen 如果我们需要在发生错误时,经过一段延时后重试,那可以这样实现: 这个操作符主要描述应该在何时重试,并且通过闭包里面返回的 Observable 来控制重试的时机,当它发出一个 error 或者 completed 事件时,就不会重试,并且将这个事件传递给到后面的观察者.
讯享网// 请求 JSON 失败时,等待 5 秒后重试, let retryDelay: Double = 5// 重试延时 5 秒 rxJson.retryWhen { (rxError: Observable<Error>) -> Observable<Int> inreturn Observable.timer(retryDelay, scheduler: MainScheduler.instance)}.subscribe(...).disposed(by: disposeBag)
// 请求 JSON 失败时,等待 5 秒后重试, // 重试 4 次后仍然失败,就将错误抛出 // 如果重试超过 4 次,就将错误抛出。如果错误在 4 次以内时,就等待 5 秒后重试 let maxRetryCount = 4 // 最多重试 4 次 let retryDelay: Double = 5// 重试延时 5 秒 rxJson.retryWhen { (rxError: Observable<Error>) -> Observable<Int> inreturn rxError.flatMapWithIndex { (error, index) -> Observable<Int> inguard index < maxRetryCount else {return Observable.error(error)}return Observable<Int>.timer(retryDelay, scheduler: MainScheduler.instance)}}.subscribe(...).disposed(by: disposeBag)
flatMapWithIndex 这个操作符,因为它可以给我们提供错误的索引数 index。然后用这个索引数判断是否超过最大重试数,如果超过了,就将错误抛出。如果没有超过,就等待 5 秒后重试。
catchError - 恢复 以在错误产生时,用一个备用元素或者一组备用元素将错误替换掉
讯享网// 先从网络获取数据,如果获取失败了,就从本地缓存获取数据 let rxData: Observable<Data> = ...// 网络请求的数据 let cahcedData: Observable<Data> = ...// 之前本地缓存的数据 rxData .catchError { _ in cahcedData } .subscribe(onNext: { date in print("获取数据成功: \(date.count)") }) .disposed(by: disposeBag)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/52029.html