RxSwift RetryWhen вызывает аномалию повторного входа - PullRequest
0 голосов
/ 25 февраля 2019

Я пытался проверить оператор 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)

С приведенным выше кодом это дает:

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

Просто интересно, кто-нибудь знает причину этой проблемы?

1 Ответ

0 голосов
/ 25 февраля 2019

Как поясняет комментарий консоли, это предупреждение может быть подавлено с помощью .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)")
    })

Я позволил себе внести несколько небольших корректировок в ваш пример кода, чтобы показать альтернативный способнапишите, что у вас есть.

Дополнительная информация

Вы попросили объяснить (а), почему добавление ObserveOn работает, и (б), почему оно необходимо.

Что .observeOn(MainScheduler.asyncInstance)Он направляет запрос в альтернативный поток, где событие может закончиться, а затем снова отправляет событие в основной поток.Другими словами, это похоже на следующее:

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

Где backgroundScheduler определяется следующим образом:

let backgroundScheduler = SerialDispatchQueueScheduler(qos: .default)

По крайней мере, это мое понимание.

А почему?это нужно, я не могу сказать.Возможно, вы нашли ошибку в библиотеке, потому что использование задержки в 1 секунду работает без наблюдения.

...