Rxswift: ControlProperty setter doesn't call underlying Control Event

Created on 10 May 2018  路  6Comments  路  Source: ReactiveX/RxSwift

Short description of the issue:

Originally reported by @arielpollack.

ControlPropertys provided in RxCocoa don't seem to call .sendActions or something similar in their setter. Which means that if you subscribe to a ControlProperty while binding events into it, you won't be getting these events emitted.

https://github.com/ReactiveX/RxSwift/blob/ba41245d067af562c6e61b9439ea1686c1fb60ad/RxCocoa/iOS/UITextField%2BRx.swift#L26-L33

Expected outcome:

Events bound into a ControlProperty should also be emitted by it.

What actually happens:

Events bound into the ControlProperty are not emitted.

Here's an example. In this one I would expect every value bound (and presented) in the UITextField to be properly emitted from the rx.text ControlProperty getter, but as you see in the console - only the initial value is emitted:

Version:
RxSwift >= 4

Platform/Environment

  • [x] iOS
  • [x] macOS
  • [x] tvOS
  • [x] watchOS
  • [x] playgrounds

How easy is to reproduce? (chances of successful reproduce after running the self contained code)

  • [x] easy, 100% repro
  • [ ] sometimes, 10%-100%
  • [ ] hard, 2% - 10%
  • [ ] extremely hard, %0 - 2%

Xcode version: 9.3

:warning: Fields below are optional for general issues or in case those questions aren't related to your issue, but filling them out will increase the chances of getting your issue resolved. :warning:

Installation method:

  • [x] CocoaPods
  • [x] Carthage
  • [x] Git submodules

I have multiple versions of Xcode installed:
(so we can know if this is a potential cause of your issue)

  • [ ] yes (which ones)
  • [x] no

Level of RxSwift knowledge:
(this is so we can understand your level of knowledge
and formulate the response in an appropriate manner)

  • [ ] just starting
  • [ ] I have a small code base
  • [x] I have a significant code base

Most helpful comment

I agree, but wanted to open the discussion so its considered.

I think it's not the expected behavior (e.g. values being "lost"), if we "naively" look into how Rx and setter/getter concepts work. But of course open to discussion and @kzaher's opinion.

All 6 comments

FWIW, this is consistent with the OS behaviour of not calling the action callback when manually setting a control value.

@fpillet That's true, but if you bind events in a non-manual, non-direct way (e.g. via a binding), it seems expected the emitted events _into_ the property will also be emitted _out_ of the property. Otherwise, it sort of breaks the getter/setter aspect of it (the getter doesn't reflect values in the setter).

Yes I agree it's a tough call, both behaviours are logical and valid. Changing this behaviour now would possibly break user code though, so this has to be carefully considered.

I agree, but wanted to open the discussion so its considered.

I think it's not the expected behavior (e.g. values being "lost"), if we "naively" look into how Rx and setter/getter concepts work. But of course open to discussion and @kzaher's opinion.

Hi @freak4pc ,

what @fpillet said is correct.

Here are the reasons why this behaves the way it does and why there is little doubt this behavior will change in future:

  • it is consistent with default non Rx behavior of Apple target/action observation APIs.
  • it is consistent with other environments I've worked with (like HTML, and some others that need to name :).
  • if we changed this behavior it would break all of my past applications (and I believe that other people will suffer the same consequences)
  • the reason why all of the existing applications would break is that view is usually observed and changes are propagated to some form of model. That model is observed and those changes are then again propagated on screen. If we just forward these events again to model, like this issue suggests, we would create stack overflow.
  • the problem is that not only that existing applications would break, but it would be really hard to write and reason about new applications because you would need to constantly think about severing that "feedback loops" somehow so that it doesn't cause stack overflow. If you fail to sever even one of these "feedback loops", you would immediately get stack overflow at app launch.
  • to sever these kinds of "feedback loops" that I've described here you would need some form of distinctUntilChanged behavior. If you have bug in equality implementation you are again risking stack overflow at app launch.
  • I can't see any practical benefits of doing this.

    • this allows people to use UI elements as their "model" => using UI as "model" always explodes except for tiny use cases and wouldn't recommend it anyway

    • it would make it more consistent => on first glance sure, but unfortunately because of all of the above they need to behave differently

I think it's not the expected behavior (e.g. values being "lost"), if we "naively" look into how Rx and setter/getter concepts work.

If you look at the small context, yes, they are "lost", but if you are looking at big context, no they aren't, they remained stored inside of your model that you are mapping to UI.

Thanks for the detailed explanation @kzaher.
I don't necessarily agree on 100% of the things mentioned here, but the argument of "this would break everything for everyone" is definitely strong enough to not "mess with this"

I also think you're right on the fact that the Model is usually the source of truth, but I still think Rx is all about data flow and routing of that data, and this sort of breaks that in its purest form. In a way, if we would "Design this from scratch today" - I would argue harder that this should be the supported behavior, but given the fact this is the status quo and would cause more harm than good to fix, I'm ok with leaving as is.

Again, highly appreciate your thoughts :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Z-JaDe picture Z-JaDe  路  3Comments

angerman picture angerman  路  3Comments

trant picture trant  路  3Comments

retsohuang picture retsohuang  路  3Comments

delebedev picture delebedev  路  3Comments