I’ve just recently switched from ASIHttpRequest library to AFNetworking. I really like the simplicity, but I am still struggling to understand how to structure my async code.
Please consider this sign up scenario.
- First I want to check if the entered email adresse is available.
- Next I want to check if the entered username is available.
- If both the above is valid and available I want to submit my real signup request.
My code would be looking something like.
- (void)signUp{
BOOL hasValidEmail = [self validateEmail:email];
BOOL hasValidUsername = [self validateUsername:username];
if(!hasValidEmail){
NSLog(@"Invalid email");
return;
}
if(!hasValidUsername){
NSLog(@"Invalid username");
return;
}
if (hasValidEmail && hasValidUsername) {
NSLog(@"Go ahead and create account");
}
}
I’m not quite sure how to structure this considering the async nature of my networking methods. Often last condition will be reached before the two previous availability checks have received their response.
The availability checking methods would look something like:
- (BOOL)validateEmail:(NSString*)email{
__block NSString* emailAlreadyExists = @"";
NSString* url = [NSString stringWithFormat:@"user/emailexists/%@", email];
[[APIClient sharedClient] getPath:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
emailAlreadyExists = [responseObject valueForKey:@"exists"];
} failure:^(AFHTTPRequestOperation *operation, NSError* error) {
NSLog(@"Email availability check failed: %@", error.localizedDescription);
}];
if([emailAlreadyExists isEqualToString:@"true"]){
return NO;
}
return YES;
}
Maybe it’s just my blocks skills that needs improving, but I’d really like to hear how you would you structure a scenario like this?
Though code samples would be “nice”, I’m really looking for patterns or good techniques you know of.
Thanks.
I usually break these things into steps and start the next step when the previous one succeeds. Blocks are great to pass along for this purpose.
This obviously wont compile, but hopefully it can give you some idea of how to do this:
If the switch is getting too long and ugly you could also make the steps into separate methods and delete the step-enum:
validateEmailWithSuccess:failurewhich continues by callingvalidateUsernameWithSuccess:failureetc.I just wanted to emphasize the state machine nature of the process in the example above.