I am using ReactiveCocoa in my iOS app for the network API requests. What if I want to show an UIAlertView and ask for user to click on the retry button and a retry on the same API call only happens when user click on the retry button, how is that supposed to do?
- (RACSignal*) fetchImportantData {
return [RACSignal createSignal: ^RACDisposable*(id<RACSubscriber> subscriber) {
return [apiCall subscribeNext:^(id x) {
[subscriber sendNext:x];
[subscriber sendCompleted];
} error:^(NSError *error) {
[subscriber sendError:error];
}];
}];
}
This should do the trick.
RACSignal * catchSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
UIAlertView * alertView = [[UIAlertView alloc]
initWithTitle:@"Try again"
message:@""
delegate:nil
cancelButtonTitle:@"No"
otherButtonTitles:@"Yes", nil];
[alertView.rac_buttonClickedSignal subscribeNext:^(NSNumber * buttonIndex) {
if (buttonIndex.integerValue != alertView.cancelButtonIndex)
{
[subscriber sendCompleted];
}
else
{
[subscriber sendError:nil];
}
}];
[alertView show];
return nil;
}];
[[[[[self fetchImportantData] catchTo:catchSignal] repeat] take:1] subscribeNext:^(id x) {
NSLog(@"NEXT: %@", x);
} error:^(NSError *error) {
NSLog(@"ERROR: %@", error);
} completed:^{
NSLog(@"COMPLETED");
}];
So what's happening here is the error from fetchImportantData
is being caught by catchTo:
, and the signal is then replaced by whatever is sent by that signal (it's kinda like flattenMap:
, but for errors). Since we now have control, we can wire up sendCompleted
to the "Yes" button and use repeat
to have the signal repeat upon completion, while wiring up sendError:
to the "No" button so that we can have all subscription stop immediately if the user doesn't want to retry.
When fetchImportantData
finally returns a non-error, it'll be sent through and completely skip our catchTo:
block, and the signal will complete thanks to our take:1
.