7

For some reason I am not getting the error message to come through. (I've simplified the code here to get straight to the point.)

// Send an error message 
_loginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendError:error]; // Pretend this is a real error
        return nil;
    }];
}];

// Subscribe to loginButton's returned signal
[_loginButton.rac_command.executionSignals subscribeNext:^(RACSignal *loginSignal) {
    [loginSignal subscribeError:^(NSError *error) {
         NSLog(@"A");
    } completed:^{
         NSLog(@"B");
    }];
}];

This prints "B". Any idea why? If -sendError: is called on the subscriber, why does the completion block receive it?

drhr
  • 2,261
  • 2
  • 17
  • 35

2 Answers2

7

This seems to work (materialize it and dematerialize it) based on this suggestion.

// Send an error message 
_loginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
    return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendError:error]; // Pretend this is a real error
        return nil;
    }] materialize];
}];

// Subscribe to loginButton's returned signal
[_loginButton.rac_command.executionSignals subscribeNext:^(RACSignal *loginSignal) {
    [[loginSignal dematerialize] subscribeError:^(NSError *error) {
         NSLog(@"A");
    } completed:^{
         NSLog(@"B");
    }];
}];
drhr
  • 2,261
  • 2
  • 17
  • 35
7

As you've discovered, RACCommand automatically catches errors within executionSignals.

This is intended to be a convenience for operators like -flatten, -concat, and -switchToLatest, which would otherwise prematurely terminate if an error occurs on any of the inner signals.

If all you care about is knowing when an error occurs, you should use RACCommand.errors instead. If you want to know where the error originated, checking the error domain and code may be easier (or at least more intuitive) than subscribing to the error event of each inner signal.

Subscriptions-within-subscriptions, and even subscriptions in general, are something of a code smell in RAC. Even if you don't want to use errors, there are generally higher-level operators to accomplish what you want (like using -map: to apply a -catch: to each inner signal).

Justin Spahr-Summers
  • 16,893
  • 2
  • 61
  • 79
  • Thanks! So, let's just say hypothetically, I wanted to performing one network operation that gives me an object, and then perform a second network op that modifies some properties of that object in the db. And I want to catch errors & display them on that 1st op. Subscribing is workable, but it's smelly? And I'd be better off using a combo of map & catch? – drhr Nov 08 '13 at 16:51
  • 1
    @drhr In that case, I think it'd be better to include the second operation within the command's signal block. If it would always run as part of that command, it's based on the values passing through that command, and informs that command's status, it seems like it logically belongs in there too. – Justin Spahr-Summers Nov 08 '13 at 16:55
  • Thanks for the idea, I'll try that out. So if I wanted to merge various `rac_command`s' unique functionality into a common, final signal (for handling different types of login methods that return the same information), I could just instantiate a `RACSignal` first, attach some 'handler' methods to it (map, catch, or the smelly subscribe), and have each `RACCommand` feed into that one signal? (BTW - Very cool library, it's really shaking up my imperative / OOP mindset..) – drhr Nov 08 '13 at 17:52
  • @drhr Hmm, it's hard to know without seeing a specific code sample. My instinct would say that you probably want to merge the results of all the commands, to create a combined signal from all of them, but that's a fairly tricky task. Unfortunately, `RACCommand` in general is fairly unintuitive, so we're hoping to simplify/replace it in 3.0 with simpler patterns. – Justin Spahr-Summers Nov 08 '13 at 18:06