0

Overview : I am using Amazon DynamoDB for my login service. And my login method looks like this in some UserAccount.m. And I am calling this class method in some LoginViewController.m on login button tap:

+ (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.
}

The issue is function returns before block executes. What I tried:

i) I read up about using dispatch groups on this SO question

ii) Tried to execute method - (AWSTask *)load:(Class)resultClass hashKey:(id)hashKey rangeKey:(id)rangeKey on main thread like this but still function returns before block execution finishes.:

   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;
    }];
});

Am I missing out something here/ doing wrong in my approach? Any suggestion towards right direction would be really helpful. Thank you!

Edit 1: Including function from where loginWithUsername class method is being called:

@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
    }


}
Community
  • 1
  • 1

2 Answers2

1

It is the basic idea of GCD that blocks are executed "in background", so the control flow can return to the sender of the message before the task is finished. This is, because the task is a potential long runner and you do not want to block the sending control flow, esp. if it is the main thread.

If you want to execute code after finishing the operation, simply add it to the block. This is the code inside login(): Add the if to the block and remove the block variable and the return value. Make the method void.

To have a general pattern:

-(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
  }
}

Please take care, that the block is potentially run on a different thread than the main thread, so you have to dispatch it on the main thread, if it is UI related.

Amin Negm-Awad
  • 16,582
  • 3
  • 35
  • 50
0

OR you could just take a page from Googles iOS framework code and do it the easy way like this:

- (void)runSigninThenInvokeSelector:(SEL)signInDoneSel {


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

}
ChuckKelly
  • 1,742
  • 5
  • 25
  • 54