Group Group Group Group Group Group Group Group Group

Getting Started With RxSwift and RxCocoa | raywenderlich.com

Use the RxSwift framework and its companion RxCocoa to take a chocolate-buying app from annoyingly imperative to awesomely reactive.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/1228891-getting-started-with-rxswift-and-rxcocoa

Validation code of the textfields contains reentrancy errors:

Reentrancy anomaly was detected.

> Debugging: To debug this issue you can set a breakpoint in /Users/michelefadda/Downloads/Materials/Chocotastic-finished/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.

I got the same message, multiple times.

@ron.kliffer Can you please help with this when you get a chance? Thank you - much appreciated! :]

I tracked this down to the manipulation of First Responder.
Evidently changing that in the midst of processing an OnNext event triggers another event, before the first one is finished.

So I tried dispatching the responder calls async on the main queue, and that eliminated the warning messages. Here is what worked:

  func advanceIfNecessary(noSpacesCardNumber: String) {
    if noSpacesCardNumber.count == cardType.value.expectedDigits {
      DispatchQueue.main.async {
        self.expirationDateTextField.becomeFirstResponder()
      }
    }
  }
  
  func advanceIfNecessary(expirationNoSpacesOrSlash: String) {
    if expirationNoSpacesOrSlash.count == 6 { //mmyyyy
      DispatchQueue.main.async {
        self.cvvTextField.becomeFirstResponder()
      }
    }
  }
  
  func dismissIfNecessary(cvv: String) {
    if cvv.count == cardType.value.cvvDigits {
      DispatchQueue.main.async {
        let _ = self.cvvTextField.resignFirstResponder()
      }
    }
  }

(Also the image name for the Credit Card Icon in the Success Scene in the storyboard should be “unknownCard”, not “UnknownCard”) .

Thanks for bringing this up

The warning can be removed by adding
.observeOn(MainScheduler.asyncInstance)
after every appearance of rx.text in setupCardImageDisplay()

I’ll make sure to make sure to update the tutorial with this fix

Thanks again

This tutorial has been updated to Swift 5 and RxSwift 5.0.
The Reentrancy warning has been removed

Is it only me or part " The Starting Point: Nonreactivity" is invalid due to the missing “updateCartButton” part… that is supposed to be in few places… ?

I think you uploaded alredy “fixed” project instead of initial materials :wink:

This could just be me but my credit card image does not update when typing out the respective credit card number. However, if I remove the throttle from the setupTextChangeHandling() then the card image updates on the text changes.

Anyone know why this is?

@ron.kliffer Can you please help with this when you get a chance? Thank you - much appreciated! :]

@ron.kliffer When working on the direct input from the text field, it says to use:
.throttle(.milliseconds(throttleIntervalInMilliseconds), scheduler: MainScheduler.instance) //2
However, in the unfinished project I seem to not be able to access “.milliseconds()”. After deep diving further, I found that in SchedulerType, RxTimeInterval = Time Interval and not DispatchTimeInterval. Was this on purpose? Is there a way to access milliseconds enum without modifying the SchedulerType?

@ron.kliffer Do you have any feedback about this? Thank you - much appreciated! :]

Hi @jsims730
I’m not sure I understand what you mean. Where can’t you access “. milliseconds”?
Can you please add a code snippet?
Thanks

@jsims730 According to https://medium.com/@freak4pc/whats-new-in-rxswift-5-f7a5c8ee48e7 Schedulers have been refactored with RxSwift 5. The described usage of milliseconds in the tutorial requires RxSwift5. The problem is that the “finished project” has been updated to RxSwift 5.0.0 and the “starter project” is still set to RxSwift 4.4.0. To fix the issue I would recommend updating RxSwift and RxCocoa to 5.0.0 within the Podfile and re-run pod install.

@ron.kliffer might make sense to also update the starter package :wink:

1 Like

@jds Thanks very much. That did the trick.

@ron.kliffer as @jds pointed out, we are unable to access “.milliseconds()” in


because RxSwift and RxCocoa are versions “4.4.0” and not “5.0.0”. I was able to circumvent the error by updating the pods to “5.0” in the starter project. I would advise to update the starter package for future students going through the lesson. Thanks!

@jsims730 Thanks for The clarification. I’ll fix it asap