概述:我使用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
}
}
答案 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];
}
}