10

I'm beginner in RXSwift, and i have problem with my code

I have code:

let dartScore = PublishSubject<Int>()
            dartScore.asObservable()
                .scan(501) { intermediate, newValue in
                    let result = intermediate - newValue
                    return result >= 0 ? result : intermediate
                }
                .do(onNext: {
                    if $0 == 0 {
                        dartScore.onCompleted()
                    }
                })
                .subscribe({
                    print($0.isStopEvent ? $0 : $0.element!)
                })
                .disposed(by: disposeBag)

            dartScore.onNext(13)
            dartScore.onNext(50)
            dartScore.onNext(60)
            dartScore.onNext(378)

And i get error:

⚠️ Reentrancy anomaly was detected. ⚠️

Debugging: To debug this issue you can set a breakpoint in /****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.

why i can't do ".onCompleted()" inside .do(onNext), and what should i do to avoid the warning?

I'm using XCode 9.0, swift 4, RXSwift 4.0.0

Thank you

Best Regards

Seishin Okigaru
  • 391
  • 1
  • 4
  • 13
  • 2
    I'm a Rx.NET guy, but I assume RxSwift behaves the same way - so don't do `.onCompleted()` inside the `do`. You probably want to use `takeWhile`. – Enigmativity Dec 03 '17 at 04:14
  • Thank you for suggest, @Enigmtivity, Regards – Seishin Okigaru Dec 04 '17 at 05:08
  • 4
    I got this issue because of completely unrelated code. If you just follow the instruction and set breakpoint and observe the stack, you can trace the issue. For me, I was observing a text field and calculating and setting other values. So the code to calculate other values was calling `view.endEditing(true)` and because of that it was going into a loop of edit and end edit.. – Skywalker Feb 05 '20 at 08:23

2 Answers2

12

You can't do the .onCompleted() inside the .onNext() because you would have the observable eating its own tail in that case. This causes a memory cycle as well.

As @Enigmativity suggested in the comments, you should use takeWhile() to handle this situation:

dartScore.asObservable()
    .scan(501) { intermediate, newValue in
        let result = intermediate - newValue
        return result >= 0 ? result : intermediate
    }
    .takeWhile { $0 != 0 }
    .subscribe({
        print($0.isStopEvent ? $0 : $0.element!)
    })

The above produces a new observable that completes when the value is 0.

Daniel T.
  • 32,821
  • 6
  • 50
  • 72
0

Not directly connected to the OP's problem, but I came here when searching for Reentrancy anomaly was detected, and for me the reason was simply that I removed an addSubview(viewInQuestion) line in the code for an NSView on MacOs, while still using the viewInQuestion in the constraints setup ... adding the viewInQuestion as a subview solved the issue.

TheEye
  • 9,280
  • 2
  • 42
  • 58