5

ReactiveCocoa can convert the signal to "hot" signal by calling its -subscribeCompleted:. But I think this method is quite verbose if you do not care about the result (i.e. no subscribers).

RACDisposable *animationDisposable = [[self play:animation] subscribeCompleted:^{
    // just to make the animation play
}];

And these 3 lines are not expressive enough to show my intention.

Is there any method for similar purpose? Thanks!

HKTonyLee
  • 3,111
  • 23
  • 34
  • It really depends on how you want to end up using it. Do you care about the results? – joshaber Mar 04 '14 at 18:57
  • I want to do nothing except making it hot (=make it run once). I want something more expressive. The above implementation is obscure. New programmer may think it is wrongly called and delete it. – HKTonyLee Mar 05 '14 at 07:09

2 Answers2

5

I want to do nothing except making it hot (=make it run once).

"You keep using that word. I do not think it means what you think it means."

A "hot signal" is a signal that sends values (and presumably does work) regardless of whether it has any subscribers. A "cold signal" is a signal that defers its work and the sending of any values until it has a subscriber. And a cold signal will perform its work and send values for each subscriber.

If you want to make a cold signal run only once but have multiple subscribers, you need to multicast the signal. Multicasting is a pretty simple concept, that works like this:

  1. Create a RACSubject to proxy the values sent by the signal you want to execute once.
  2. Subscribe to the subject as many times as needed.
  3. Create a single subscription to the signal you want to execute only once, and for every value sent by the signal, send it to the subject with [subject sendNext:value].

However, you can and should use RACMulticastConnection to do all of the above with less code:

RACMulticastConnection *connection = [signal publish];
[connection.signal subscribe:subscriberA];
[connection.signal subscribe:subscriberB];
[connection.signal subscribe:subscriberC];
[connection connect]; // This will cause the original signal to execute once.
                      // But each of subscriberA, subscriberB, and subscriberC
                      // will be sent the values from `signal`.
erikprice
  • 6,240
  • 3
  • 30
  • 40
  • Thank a lot. But this is not what I want. I want to fire a signal that I don't care about the result (ie. no subscriber). It is hard to do in pure functional environment but it happens in stateful environment. It is analogue to `nil` delegate. If I don't need callback, I can safely ignore the delegate property, instead of conforming the whole delegate by implementing tons of empty functions. It is less expressive. – HKTonyLee Mar 07 '14 at 02:30
  • I don't know if my question is useful :-/ I think some novices (include me, LOL) will also ask similar question. – HKTonyLee Mar 07 '14 at 04:22
  • The point of ReactiveCocoa is to let you elegantly handle the *results* of work. If all you want is for some work to happen as a side effect and you don't care about handling the results, then ReactiveCocoa doesn't really do much for you. – erikprice Mar 08 '14 at 20:18
  • @erikprice can you show example of a hot and a cold signal? – onmyway133 Mar 31 '15 at 17:24
  • 3
    @onmyway133 The most common example of a cold signal is one which, when subscribed to, performs an HTTP request. For every subscriber, a separate independent request is made, and each subscriber gets its own response. It's cold because until there is a subscriber, it doesn't actually "do" anything. One example of a hot signal is one which constantly delivers the current mouse X,Y coordinates. Regardless of how many subscribers there are, all subscribers get sent the same value whenever a new value is sent. And whenever there are no subscribers, values are "missed" (or dropped). – erikprice Apr 02 '15 at 14:37
4

If you do not care about the output of the signal (and for some reason you really want play to be a signal), you may want to make a command. A command causes a signal to be executed via some sort of event (such as a ui button press or other event). Simply create the Signal, add it to a command, then when you need to run it, execute it.

@weakify(self);
RACCommand * command = [[RACCommand alloc] initWithSignalBlock:^(id input) {
  @strongify(self);
  return [self play:animation];
}];

//This causes the signal to be ran
[command execute:nil];

//Or you could assign the command to a button so it is executed 
// when the button is pressed
playButton.rac_command = command;
Brett
  • 769
  • 6
  • 16
  • Thanks! I think I had some wrong concept about reactive programming. I am still figuring it out ;-) – HKTonyLee May 14 '14 at 02:18
  • !!!! This thread has explained far better what a RACCommand is in essence than ANY ReactiveCocoa documentation. Thanks! – fatuhoku Oct 01 '14 at 08:19