0

I have three signals that represent interdependent properties: city, performer and event.

If city is changed or set to nil, it also sets the performer and event to nil.

When this happens, the combineLatest subscription on those signals fires three times - once for the city, then again for the performer being set to nil, then again for the event being set to nil.

The combineLatest call is needed on all three as an event or performer might change without the city changing.

Is there a better pattern (ideally not using throttling - deliberately slowing down my app is a painful solution) that allows me to have combineLatest only be called a single time? Ideally, as soon as the city changes, performer and event are set to nil and THEN the combineLatest method is called.

Thank you!

Rich Lowenberg
  • 1,089
  • 1
  • 8
  • 12

3 Answers3

2

If you're using RACObserve() on the properties, you need to set the backing instance variables for the performer and event properties to nil without calling those properties' setter methods (when the city property gets changed):

- (void)setCityWithNillingBehavior:(City *)city
{
    _event = nil;
    _performer = nil;
    self.city = city;
}

I know you're looking for a way to do this within the ReactiveCocoa framework, but it's not really possible unless you want to get involved in some messy stateful trickery (like using sentinel city that triggers an -if:then:else:). Yuck.

erikprice
  • 6,240
  • 3
  • 30
  • 40
  • Valid solution - seems like the kind of thing that could easily get me into trouble down the road though, I think I'd sooner resort to a throttle. Thank you for giving me something workable though, it's a smart solution! – Rich Lowenberg Sep 11 '14 at 16:13
2

There isn't any way you can do this directly with ReactiveCocoa. Your combineLatest logic is called whenever any of the three properties change, however the properties all affect each other. When one changes, the other two change.

Conceptually combineLatest is doing the right thing!

What about a very short throttle? Even a zero second delay? This is actually a common trick in JavaScript applications where a setTimeout(0) is used to defer some code to the next run loop:

Why is setTimeout(fn, 0) sometimes useful?

if your combineLatest code is performing UI logic - your users will not notice the difference!

Community
  • 1
  • 1
ColinE
  • 68,894
  • 15
  • 164
  • 232
  • 1
    Thanks for the reply Colin! Your work has helped me learn a ton and it's awesome to get your help on this. It sounds like throttling very slightly is the way to do this. It is UI, and I agree users probably won't notice, it just feels a little messy to me. I'll try the 0 second delay, that's an interesting insight. – Rich Lowenberg Sep 11 '14 at 16:14
2

Are nil updates important to your +combineLatest: subscribers? If not, you could apply ignore:nil to those property observations.

Dave Lee
  • 6,299
  • 1
  • 36
  • 36
  • I didn't know about ignore:nil - very useful, thanks! Unfortunately in this case nil values are important. But thanks for the tip - that will come in handy elsewhere too. – Rich Lowenberg Sep 16 '14 at 03:55