2015-11-03 192 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通話。