Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Does RACCommand's block return a signal?

I've been learning a lot about ReactiveCocoa but one thing still puzzles me: why does the signal block on RACCommand return a signal itself?

I understand the use cases of RACCommand, its canExecute signal and signal block, and how it can be hooked up to UI elements. But what case would there be ever for returning something other than [RACSignal empty]?

infoButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
    // Do stuff

    return [RACSignal empty];
}];
like image 221
Ash Furrow Avatar asked Oct 18 '13 02:10

Ash Furrow


2 Answers

There are exceptions to every rule, but generally you want all your "// Do stuff" to be captured by the returned signal. In other words, your example would be better as:

infoButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id input) {
    return [RACSignal defer:^{
        // Do stuff

        return [RACSignal empty];
    }];
}];

The direct benefit of this change is that, for the duration of "// Do stuff", your infoButton will be disabled, preventing it from being clicked/tapped until the returned signal has completed. In your original code, the "do stuff" is outside of the signal, and as such your button won't be disabled properly.

For work that doesn't have much latency, for example making UI changes in response to a button tap, then the enabled/disabled feature of RACCommand doesn't buy you much. But if the work is a network request, or some other potentially long running work (media processing for example), then you definitely want all of that work captured within a signal.

like image 126
Dave Lee Avatar answered Oct 20 '22 10:10

Dave Lee


Imagine you have a command that should load list of items from network. You could use side effects in signal block or return a signal that would actually send these items. In the latter case you can do the following:

RAC(self, items) = [loadItems.executionSignals switchToLatest];

Also all errors sent by signal would be redirected to errors signal, so:

[self rac_liftSelector:@selector(displayError:) 
           withSignals:loadItems.errors, nil];

It's impossible with [RACSignal empty]-powered commands.

like image 7
Nikolay Kasyanov Avatar answered Oct 20 '22 09:10

Nikolay Kasyanov