Warm tip: This article is reproduced from stackoverflow.com, please click
swift reactive-programming rx-swift reactive reactivex

Reactive asynchronous feedback system with RxSwift

发布于 2020-03-31 22:57:18

I am designing a call manager with the help of RXSwift (ReactiveX) that continuously interacts with an API. The call manager comprises several objects that itself comprises an indicator (indicating status information loaded from the API) and control (requests to be sent to the API).

class CallManagerObjectA() {
  var control = PublishSubject<String>()
  var indicator = BehaviorSubject<String>(value: "string status")
}

Within the call manager, a scheduler regularly provides new values to the indicator observable:

<... API response ...>
indicator.onNext(newValue)

Somewhere else in a view controller, the indicator will be observed for a label:

indicator.subscribe(onNext: { label.stringValue = $0 })

Within the same view controller, the user can control the object status via GUI elements continuously:

control.onNext(commandValue)

Within the call manager, the control will be observed for an API call:

control.subscribe(onNext: { (command) in
  // API request call 
})

So far so good, this is working very well with reactive patterns. Now, I am looking for a good solution to handle errors, if the call manager recognizes errors during the API interaction and show these errors to the user in the view controller. I was immediately thinking of something like this:

// Call manager recognizes the error
control.onError(error)

...

// Call manager ignores errors for the subscriber
control.retry().ignoreErrors().subscribe(onNext: { (command) in
  // API request call 
})

...

// View controller shows the errors
indicator.subscribe(onNext: { label.stringValue = $0 })
control.subscribe(onError: { print("error", $0) })

This however ends up in an infinite loop. I fear that I have a fundamental understanding issue with reactive programming, or I miss something very important, but I am not able to understand how the handle errors in this reactive pattern environment.

Questioner
Maschina
Viewed
21
Daniel T. 2020-02-01 21:23

Based on the code you have shown, you have a big misunderstanding, not just with how to handle Errors, but with how to program reactively in general. Try watching this video "Reactive Programming: Why It Matters"

To answer your specific question, there are two misunderstandings here:

  1. When you call control.onError(_:) it will be the last call you will be able to make on control. Once it emits an error it will stop working.

  2. The retry() operator asks its source to "try again on Error". If it's source is determinate, then it will just do the exact same thing it did before and emit the exact same output (i.e., the same error it emitted last time.) In the case of a PublishSubject, it doesn't know why onError was called. So the best it can do is just emit the error again.

Honestly, I consider this a bug in the API because subscribing to a publish subject that emitted an error at some point in the past should just do nothing. But then, you wouldn't be asking why you got an infinite loop. Instead you would be asking why your control stopped emitting events.