目标c-如何确保在执行任何其他代码之前执行块?

时间:2015-07-21 02:43:52

标签: ios objective-c amazon-dynamodb

概述:我使用Amazon DynamoDB作为登录服务。我的登录方法在某些UserAccount.m中看起来像这样。我在登录按钮上点击一些LoginViewController.m中调用此类方法:

+ (BOOL)loginWithUsername:(NSString *)username password:(NSString *)password{

AWSDynamoDBObjectMapper *dynamoDBObjectMapper = [AWSDynamoDBObjectMapper defaultDynamoDBObjectMapper];
BOOL __block isLoginSuccessful = NO;

[[dynamoDBObjectMapper load:[User class] hashKey:username rangeKey:@"key"]
 continueWithBlock:^id(AWSTask *task) {
     if (task.error) {
         NSLog(@"The request failed. Error: [%@]", task.error);
     }
     if (task.exception) {
         NSLog(@"The request failed. Exception: [%@]", task.exception);
     }
     if (task.result) {
        //Do something with the result.             
         User *user = task.result;   // User is a model I'm using 
         NSLog(@"pass: %@", user.password);

         // Check returned password from DynamoDB with user-supplied password.
         if ([user.password isEqualToString:password]) {
             isLoginSuccessful = YES;
         }
     }
     return nil;
 }];

 return isLoginSuccessful;  // <-- Issue: function returns before block executes and isLoginSuccessful value is changed.
}

问题是在块执行之前函数返回。我尝试了什么:

i)我读到了关于使用dispatch groups on this SO question

的信息

ii)尝试在主线程上执行方法- (AWSTask *)load:(Class)resultClass hashKey:(id)hashKey rangeKey:(id)rangeKey,但仍然在块执行完成之前返回函数。:

   dispatch_async(dispatch_get_main_queue(), ^{
    [[dynamoDBObjectMapper load:[User class]
                        hashKey:username
                       rangeKey:@"key"] continueWithExecutor:[AWSExecutor mainThreadExecutor] withBlock:^id(AWSTask *task) {
        if (!task.error) {
            User *user = task.result;
            NSLog(@"pass: %@", user.password);
            //Do something with the result.
            if ([user.password isEqualToString:password]) {
                isLoginSuccessful = YES;
            }
        } else {
            NSLog(@"Error: [%@]", task.error);


        }
        return nil;
    }];
});

我在这里错过了什么/做错了吗?任何朝向正确方向的建议都会非常有帮助。谢谢!

  

编辑1:包含调用loginWithUsername类方法的函数:

@IBAction func login(sender: AnyObject) {

    if(UserAccount.loginWithUsername(txtEmail.text, password: txtPassword.text)){
        println("SUCCESS")
        lblIncorrect.hidden = true
    }
    else{
        println("Incorrect username/password")
        lblIncorrect.hidden = false
    }


}

2 个答案:

答案 0 :(得分:1)

GCD的基本思想是块“在后台”执行,因此控制流可以在任务完成之前返回到消息的发送者。这是因为任务是一个潜在的长跑者,你不想阻止发送控制流,尤其是。如果它是主线程。

如果要在完成操作后执行代码,只需将其添加到块中即可。这是login()内的代码:将if添加到块中并删除块变量和返回值。制作方法void

要有一般模式:

-(IBAction)doSomething:(id)sender
{
   [self executeOperation]; // Method becomes void
   // Remove code processing on result
}

-(void)executeOperation // Method becomes void
{
  [receiver longRunnerWithBlock:^(id result)
  {
    …
    // Add code processing on result
  }
}

请注意,该块可能在与主线程不同的线程上运行,因此如果它与UI相关,则必须在主线程上调度它。

答案 1 :(得分:0)

或者你可以从Googles iOS框架代码中获取一个页面并按照这样简单的方式执行:

- (void)runSigninThenInvokeSelector:(SEL)signInDoneSel {


    if (signInDoneSel) {
        [self performSelector:signInDoneSel];
    }

}