简体   繁体   English

RxSwift RetryWhen 导致重入异常

[英]RxSwift RetryWhen causes Reentrancy Anomaly

I have been trying to test on retryWhen operator on RxSwift and I have encountered the Reentrancy Anomaly issue, here's the code:我一直在尝试在retryWhen上测试retryWhen运算符, 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)

With the code above it gives:上面的代码给出了:

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

Just wondering if anyone knows the cause of this issue?只是想知道是否有人知道这个问题的原因?

As the console comment explains, this warning can be suppressed using .observeOn(MainScheduler.asyncInstance) as in:正如控制台注释所解释的那样,可以使用.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)")
    })

I took the liberty of making a few minor adjustments to your example code to show an alternate way to write what you have.我冒昧地对您的示例代码进行了一些小的调整,以展示编写您所拥有内容的另一种方式。

Additional Information附加信息

You asked to explain (a) why adding the ObserveOn works and (b) why it is needed.您要求解释 (a) 为什么添加 ObserveOn 有效以及 (b) 为什么需要它。

What .observeOn(MainScheduler.asyncInstance) does is route the request to an alternate thread where the event can finish and then emit the event again on the main thread. .observeOn(MainScheduler.asyncInstance)所做的是将请求路由到事件可以完成的备用线程,然后在主线程上再次发出事件。 In other words, it's like doing this:换句话说,就像这样做:

.observeOn(backgroundScheduler).observeOn(MainScheduler.instance)

Where backgroundScheduler is defined like:其中backgroundScheduler定义如下:

let backgroundScheduler = SerialDispatchQueueScheduler(qos: .default)

At least that's my understanding.至少这是我的理解。

As for why it's needed, I can't say.至于为什么需要它,我不能说。 You might have found a bug in the library because using a 1 second delay works fine without the observeOn.您可能在库中发现了一个错误,因为在没有observeOn 的情况下使用 1 秒延迟可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM