Owen Zhao
Owen Zhao

Reputation: 3355

How to suppress a specify error in RxSwift?

When run in Debug scheme, there is a fatal error in line 30, if you code are something like this.

https://github.com/ReactiveX/RxSwift/blob/master/RxSwift/Observables/Implementations/Sink.swift

rxFatalError("Warning: Recursive call or synchronization error!")

If I choose run scheme from Debug to Release. The fatal error won't show. But I wonder if I could do something to suppress it.

class ViewController4: UIViewController {
    var v = Variable(0)
    var disposeBag = DisposeBag()
    var notiBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        v.asObservable()
            .subscribe(onNext: { _ in
                let noti = Notification(name: MyNotificationName)
                NotificationCenter.default.post(noti)
            })
            .disposed(by: disposeBag)

        NotificationCenter.default.rx.notification(MyNotificationName)
            .subscribe(onNext: { [unowned self] _ in
                if self.v.value == 10 { self.notiBag = DisposeBag() }
                else { self.v.value += 1 } // this line cause the issue
                print(self.v.value)
                self.counterTextView.text! += "\(self.v.value)\n"
            })
            .disposed(by: notiBag)
        v.value = 0
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBOutlet weak var counterTextView: UITextView!
}

let MyNotificationName = Notification.Name.init(rawValue: "My Notification Name")

Upvotes: 1

Views: 1108

Answers (3)

Daniel T.
Daniel T.

Reputation: 33967

You can have the same behavior without using the Variable.

    let scheduler = SerialDispatchQueueScheduler(qos: .userInitiated)
    NotificationCenter.default.rx.notification(MyNotificationName)
        .take(9)
        .observeOn(scheduler)
        .subscribe(onNext: { _ in
            let noti = Notification(name: MyNotificationName)
            print("foo")
            NotificationCenter.default.post(noti)
        }).disposed(by: bag)

    let noti = Notification(name: MyNotificationName)
    NotificationCenter.default.post(noti)

Upvotes: 1

Owen Zhao
Owen Zhao

Reputation: 3355

I have mark @thierryb 's answer as the correct one. The known correct answers are as below.

NotificationCenter.default.rx.notification(MyNotificationName)
    .observeOn(MainScheduler.asyncInstance)
    .subscribe(onNext: { [unowned self] _ in
        if self.v.value == 10 { self.notiBag = DisposeBag() }
        else { self.v.value += 1 } // this line cause the issue
        print(self.v.value)
        self.counterTextView.text! += "\(self.v.value)\n"
    })
    .disposed(by: notiBag)

or

NotificationCenter.default.rx.notification(MyNotificationName)
    .subscribe(onNext: { [unowned self] _ in
        DispatchQueue.main.async { [unowned self] in
            if self.v.value == 10 { self.notiBag = DisposeBag() }
            else { self.v.value += 1 } // this line cause the issue
            print(self.v.value)
            self.counterTextView.text! += "\(self.v.value)\n"
        }
    })
    .disposed(by: notiBag)

Upvotes: 1

thierryb
thierryb

Reputation: 3728

This fatal error appears only in debug mode because it calls rxFataError only when you compile for debug. Its defined like this:

#if DEBUG
    if AtomicIncrement(&_numberOfConcurrentCalls) > 1 {
        rxFatalError("Warning: Recursive call or synchronization error!")
    }

    defer {
        _ = AtomicDecrement(&_numberOfConcurrentCalls)
    }
#endif

I just got this fatal error after an RxSwift update (3.4.0). My code updated Variable value in concurrent queue. Changed to serial queue fixed this crash.

Thierry

Upvotes: 1

Related Questions