ios - RxSwift RetryWhen 导致可重入异常
问题描述
我一直在尝试对retryWhen
operator on进行测试,RxSwift
但遇到了Reentrancy Anomaly
问题,代码如下:
Observable<Int>.create { observer in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onNext(4)
observer.onError(RequestError.dataError)
return Disposables.create()
}
.retryWhen { error in
return error.enumerated().flatMap { (index, error) -> Observable<Int> in
let maxRetry = 1
print("index: \(index)")
return index < maxRetry ? Observable.timer(1, scheduler: MainScheduler.instance) : Observable.error(RequestError.tooMany)
}
}
.subscribe(onNext: { value in
print("This: \(value)")
}, onError: { error in
print("ERRRRRRR: \(error)")
})
.disposed(by: disposeBag)
使用上面的代码,它给出:
This: 1
This: 2
This: 3
This: 4
index: 0
This: 1
This: 2
This: 3
This: 4
index: 1
⚠️ Reentrancy anomaly was detected.
> Debugging: To debug this issue you can set a breakpoint in /Users/tony.lin/Documents/Snippet/MaterialiseTest/Pods/RxSwift/RxSwift/Rx.swift:97 and observe the call stack.
> Problem: This behavior is breaking the observable sequence grammar. `next (error | completed)?`
This behavior breaks the grammar because there is overlapping between sequence events.
Observable sequence is trying to send an event before sending of previous event has finished.
> Interpretation: This could mean that there is some kind of unexpected cyclic dependency in your code,
or that the system is not behaving in the expected way.
> Remedy: If this is the expected behavior this message can be suppressed by adding `.observeOn(MainScheduler.asyncInstance)`
or by enqueing sequence events in some other way.
⚠️ Reentrancy anomaly was detected.
> Debugging: To debug this issue you can set a breakpoint in /Users/tony.lin/Documents/Snippet/MaterialiseTest/Pods/RxSwift/RxSwift/Rx.swift:97 and observe the call stack.
> Problem: This behavior is breaking the observable sequence grammar. `next (error | completed)?`
This behavior breaks the grammar because there is overlapping between sequence events.
Observable sequence is trying to send an event before sending of previous event has finished.
> Interpretation: This could mean that there is some kind of unexpected cyclic dependency in your code,
or that the system is not behaving in the expected way.
> Remedy: If this is the expected behavior this message can be suppressed by adding `.observeOn(MainScheduler.asyncInstance)`
or by enqueing sequence events in some other way.
ERRRRRRR: tooMany
只是想知道是否有人知道这个问题的原因?
解决方案
正如控制台注释所解释的,可以使用.observeOn(MainScheduler.asyncInstance)
如下方式抑制此警告:
Observable<Int>.from([1, 2, 3, 4]).concat(Observable.error(RequestError.dataError))
.observeOn(MainScheduler.asyncInstance) // this is the magic that makes it work.
.retryWhen { error in
return error.enumerated().flatMap { (index, error) -> Observable<Int> in
let maxRetry = 1
print("Index:", index)
guard index < maxRetry else { throw RequestError.tooMany }
return Observable.timer(1, scheduler: MainScheduler.instance)
}
}
.subscribe(onNext: { value in
print("This: \(value)")
}, onError: { error in
print("ERRRRRRR: \(error)")
})
我冒昧地对您的示例代码进行了一些小的调整,以展示另一种编写您所拥有的内容的方法。
附加信息
您要求解释 (a) 为什么添加 ObserveOn 有效,以及 (b) 为什么需要它。
什么.observeOn(MainScheduler.asyncInstance)
是将请求路由到事件可以完成的备用线程,然后在主线程上再次发出事件。换句话说,就像这样做:
.observeOn(backgroundScheduler).observeOn(MainScheduler.instance)
其中backgroundScheduler
定义如下:
let backgroundScheduler = SerialDispatchQueueScheduler(qos: .default)
至少这是我的理解。
至于为什么需要它,我不能说。您可能在库中发现了一个错误,因为在没有 observeOn 的情况下使用 1 秒延迟可以正常工作。
推荐阅读
- java - 如何将java web应用程序连接到mysql
- javascript - 在反应中显示来自json数据库的图像
- ios - 如何在 xcode 自动布局中使对象自动调整大小?
- android - 我们可以在 Flutter 项目中在 Android 设备上使用等效的 SF Symbol 吗?
- java - 何时以及如何在 java 中调用超级构造函数
- c++ - 单元管理函数 c++
- php - 当我将 require_once() 与 ampps 一起使用时,出现 Permission denied 错误
- html - HTML 表单使图像成为复选框
- r - 蒙特卡罗模拟的 R 问题
- sql - Excel ADO 强制数据类型