在控制器中构建异步网络代码

时间:2012-04-24 19:35:06

标签: iphone ios afnetworking

我刚刚从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;   
}

也许它只是我需要改进的积木技能,但我真的很想听听你如何构建这样的场景?

虽然代码示例会很好"但我真的在寻找您所知道的模式或技巧。

感谢。

1 个答案:

答案 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等。

我只是想在上面的例子中强调该过程的状态机性质。