我刚刚从ASIHttpRequest库切换到AFNetworking。我非常喜欢简单,但我仍然在努力理解如何构建我的异步代码。
请考虑此注册方案。
我的代码看起来像。
- (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");
}
}
考虑到我的网络方法的异步特性,我不太确定如何构建它。通常,在前两次可用性检查收到响应之前,将达到最后一个条件。
可用性检查方法如下所示:
- (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;
}
也许它只是我需要改进的积木技能,但我真的很想听听你如何构建这样的场景?
虽然代码示例会很好"但我真的在寻找您所知道的模式或技巧。
感谢。
答案 0 :(得分:0)
我通常将这些事情分解为步骤,并在前一个步骤成功时开始下一步。为此目的,块很好地传递。
这显然不会编译,但希望它可以让你知道如何做到这一点:
typedef enum
{
SignupErrorNetworkError,
SignupErrorEmailAlreadyTaken,
SignupErrorUsernameAlreadyTaken,
} SignupError;
typedef enum
{
// These steps must be performed in this order.
SignupStepValidateEmail,
SignupStepValidateUsername,
SignupStepCreateAccount,
} SignupStep;
typedef void (^SignupSuccessBlock)();
typedef void (^SignupFailureBlock)(SignupError reason);
// Call this to sign up.
- (void)signupWithSuccess:(SignupSuccessBlock)success failure:(SignupFailureBlock)failure
{
// Start the first step of the process.
[self performSignupStep:SignupStepValidateEmail success:success failure:failure];
}
// Internal method. Don't call this from outside.
- (void)performSignupStep:(SignupStep)step success:(SignupSuccessBlock)success failure:(SignupFailureBlock)failure
{
switch (step)
{
case SignupStepValidateEmail:
[[APIClient sharedClient] getPath:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([responseObject valueForKey:@"exists"])
{
if (failure) failure(SignupErrorEmailAlreadyTaken);
return; }
}
// Start next async step in signup process.
[self performSignupStep:SignupStepValidateUsername success:success failure:failure];
} failure:^(AFHTTPRequestOperation *operation, NSError* error) {
if (failure) failure(SignupErrorNetworkError);
}];
break;
case SignupStepValidateUsername:
// Similar to the step above. Starts the create account step on success.
break;
case SignupStepCreateAccount:
// Similar to the step above. Call the success block when done.
break;
}
}
如果开关过长且过于丑陋,您也可以将步骤分成单独的方法并删除步骤枚举:validateEmailWithSuccess:failure
,继续调用validateUsernameWithSuccess:failure
等。
我只是想在上面的例子中强调该过程的状态机性质。