There is a library called Reactive Cocoa that is awesome but hard to get used to.
An easier way to achieve your goal, but not so awesome, is using cover locks around the UIAlertView and UIActionSheet. It is also assumed that you have reverse blocks in the network code.
Example:
- (void)showActionSheet { BlockActionSheet *sheet = [BlockActionSheet sheetWithTitle:@"Choose one"]; __weak BlockActionSheet *weakSheet = sheet; [sheet addButtonWithTitle:@"Blue" atIndex:0 block:^{ [self downloadFileFromServerSuccessBlock:^{ //YAY } failureBlock:^{ BlockAlertView *alert = [BlockAlertView alertWithTitle:@"Failure" message:@"Something Went Wrong"]; [alert addButtonWithTitle:@"Try Again" block:^{ [weakSheet showInView:self.view]; }]; [alert setCancelButtonWithTitle:@"Cancel" block:nil]; }]; }]; [sheet addButtonWithTitle:@"Black" atIndex:1 block:^{ //something else }]; [sheet setCancelButtonWithTitle:@"Cancel" block:nil]; [sheet showInView:self.view]; }
So the last line of β[sheet showInView: self.view]β starts everything. If they select Blue, then this block is called. Network code also supports blocks, so you get a successful and fail-safe callback from there. If this fails, you will see a blocking pop-up warning that causes the ActionSheet to show itself again and again.
Hope this helps at least a little. There are also probably some strong links occurring with the call to "self.view", so I will also make a weak link to the view.
Here is an example of ReactiveCocoa. I am very new to this structure, so I hope that I use it correctly.
- (void)sendAuthentication { RACSubscribable *sub = [[ThaweQBRequestController logInWithUsername:self.thaweusername password:self.thawepassword] asMaybes]; [[sub where:^(id x) { return [x hasObject]; }] subscribeNext:^(id _) { NSArray *array = [_ object]; NSString *errcode = [array objectAtIndex:0]; if (errcode.boolValue == YES)
Then we get to the network request controller that I have.
+ (RACAsyncSubject *)logInWithUsername:(NSString *)username password:(NSString *)password { RACAsyncCommand *loginCommand = [RACAsyncCommand command]; RACAsyncSubject *subject = [RACAsyncSubject subject]; RACSubscribable *loginResult = [[[loginCommand addAsyncBlock:^(id _) { return [self authenticateUser:username password:password]; }] repeat] asMaybes]; [[[loginResult where:^(id x) { return [x hasError]; }] select:^(id x) { return [x error]; }] subscribeNext:^(id x) { NSLog(@"network error omg: %@", x); }]; [loginResult where:^(id x) { return [x hasObject]; }] subscribeNext:^(id _) { NSNumber *number; NSString *errcode = [_ object]; if (errcode.intValue == 0) number = [NSNumber numberWithBool:YES] ?: [NSNumber numberWithBool:NO]; [subject sendNext:[NSArray arrayWithObjects:number, username, password, nil]]; [subject sendCompleted]; }]; [loginCommand execute:@"This value gets transfered to the addAsyncBlock:^(id _) block above."]; return subject; } + (RACAsyncSubject *)authenticateUser:(NSString *)username password:(NSString *)password { QBRequest *request = [[QBRequest alloc] init]; [request setQuickBaseAction:QBActionTypeAuthenticate]; [request setURLString:URLstring withDatabaseID:nil]; [request setApplicationToken:appToken]; return [request sendAndPersist:NO username:username password:password]; }
And now we are in my actual network shell, which knows when the request completed or failed or something else.
- (RACAsyncSubject *)sendAndPersist:(BOOL)persist username:(NSString *)username password:(NSString *)password { self.subject = [RACAsyncSubject subject]; [anOp onCompletion:^(MKNetworkOperation *completedOperation) { dispatch_async(background_parseSave_queue(), ^{ [self updateDatabase]; }); } onError:^(NSError *error) { [subject sendError:error]; }]; [engine enqueueOperation:anOp]; return subject; }
And finally, to give you an idea of ββwhen I have the [sendNext:] item in my parser. Self.currentParsedCharacterData is an NSString value with an integer and integer value.
else if ([elementName isEqualToString:@"errcode"]) { if ([self.action isEqualToString:@"API_Authenticate"]) { [subject sendNext:[self.currentParsedCharacterData copy]]; [subject sendCompleted]; } }
I know this is a long time, but I really wanted to give some code examples.