2015-11-03 193 views
1

我正在开发一个登录页面的应用程序。当应用程序启动时,将显示登录屏幕,并且只有连接后才能访问该应用程序。要连接到应用程序,请输入您的用户名和密码。当您按下“连接”按钮,包含用户名和密码JSON数据被发送到Web服务,它检查是否存在的凭据。如果它们存在,服务器发送一个包含“exists”的json文件:“true”登录并完成处理

问题是检查此Json文件的代码位于NSURLSession的completionHandler中,并且该方法在Json数据之前返回“NO”被检查,所以我无法连接到我的应用程序。由于这很难解释,这里是我的代码:

GSBconnexion.m:

#import "GSBconnexion.h" 

@implementation GSBconnexion 





-(bool)logConnexionWithUserName:(NSString *)username 
        password:(NSString *)password{ 


    __block BOOL allowConnexion; 
    NSDictionary *connexion = @{ 
           @"username": username, 
           @"password": password, 
           @"target": @"app" 
           }; 


    NSError *error; 
    NSData *jsonLogData = [NSJSONSerialization dataWithJSONObject:connexion             options:NSJSONWritingPrettyPrinted 
                error:&error]; 


if (! jsonLogData) { 
    NSLog(@"Got an error: %@", error); 
} 



NSData *logData = jsonLogData; 
NSString *testString = [[NSString alloc] initWithData:logData encoding:NSUTF8StringEncoding]; 
NSString *logLength = [NSString stringWithFormat:@"%lu", (unsigned long)[testString length]]; 
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 
[request setURL:[NSURL URLWithString:@"http://192.168.5.133:1337/login"]]; 
[request setHTTPMethod:@"POST"]; 
[request setValue:logLength forHTTPHeaderField:@"Content-lenght"]; 
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; 
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
[request setHTTPBody:logData]; 
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; 
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){ 
    NSDictionary *serverResponse = [NSJSONSerialization JSONObjectWithData:data options: 
            NSJSONReadingMutableContainers error:&error]; 

    int canIConnect = [serverResponse[@"exist"] intValue]; 

    NSLog(@"%d",canIConnect); 




if (canIConnect == 1) { 
     NSLog(@"OKKK"); 
     allowConnexion = YES; 
     NSString *sessionID = [[NSString alloc]initWithString:serverResponse[@"_id"]]; 
     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 
     [userDefaults setObject:sessionID forKey:@"SessionID"]; 
     [userDefaults synchronize]; 

      NSLog(@"ID Session:%@",[userDefaults objectForKey:@"sessionID"]); 
    } 

    else { 

     allowConnexion=NO; 
    } 

}] resume]; 

NSLog(@"JSON envoyé: \n\n%@",testString); 

return allowConnexion; 
} 



@end 

GSBLoginController:

- (IBAction)connect:(id)sender { 

    connectButton.hidden = YES; 
    loading.hidden = NO; 

    UIViewController* homePage = [self.storyboard instantiateViewControllerWithIdentifier:@"homePage"]; 

    GSBconnexion *login = [[GSBconnexion alloc]init]; 

    NSString *username = [[NSString alloc]initWithFormat:@"%@",usernameTextField.text]; 
    NSString *password = [[NSString alloc]initWithFormat:@"%@",pwdTextField.text]; 

    BOOL authorized = [login logConnexionWithUserName:username password:password]; 
    if (authorized) { 
     [self presentViewController:homePage animated:YES completion:nil]; 
    } 

    else { 
     connectButton.hidden = NO; 
     loading.hidden=YES; 
     [email protected]""; 
     [email protected]""; 
     errorLabel.text = @"Connexion impossible, merci de réessayer.\nSi le problème persiste, veuillez contacter un administrateur."; 
    } 

    NSLog(authorized ? @"Yes" : @"No"); 
} 

我希望你明白我的意思,感谢您的帮助!

西蒙

回答

1

的问题是,你希望从被异步执行的方法的返回值。所以基本上return allowConnexion立即发生,即使dataTask是仍然在后台持续。因此,你依赖于一个不正确的值。基本上你想要做的就是复制dataTask中w/a完成处理程序中发生的事情。

所以,你可以这样说:typedef void (^CompletionBlock) (BOOL isFinished);

然后更改登录方法,包括完成块作为其最后一个参数和返回任何结果:

-(void)logConnexionWithUserName:(NSString *)username 
        password:(NSString *)password 
        withCompletion:(CompletionBlock)completionBlock 

然后dataTask的completionHandler内拨打completionBlock传球在值allowConnexion

最后,一旦你已经做了所有在您登录视图控制器,你将实现这种新方法,并完成块内,你可以相应地更新你的看法。它会是这个样子:

- (void)thingWithCompletion:(CompletionBlock)completionBlock 
{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     completionBlock(YES); 
    }); 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [self thingWithCompletion:^(BOOL isFinished) { 
     //update UI 
    }]; 
} 

注意,因为你是在后台线程,并要更新完成UI,你会希望派遣到主队列为好。这就是为什么completionBlock(YES);呼叫被包裹在dispatch_async通话。