Reputation: 2002
I'm developing an application that should login to a remote service in the first view controller I create a UI to insert username and password. When I press on the button login I make the following check:
The method to call the external class is the follow:
- (BOOL)loginSuccessWith:(NSString*)userName and:(NSString*)password {
ConnectionHandler *connectionHandler = [[ConnectionHandler alloc]init];
if ([connectionHandler startConnectionToServer:@"serverAddress" andUsername:userName withPassword:password andInstallationId:[[NSUserDefaults standardUserDefaults] objectForKey:@"instId"]]) {
return YES;
} else {
return NO;
}
}
As you can see if the method return YES or NO if the user can be logged or not.
In the ConnectionHandler
class I wrote the following code:
#import "ConnectionHandler.h"
@interface ConnectionHandler() {
BOOL authenticated;
}
@end
@implementation ConnectionHandler
- (BOOL)startConnectionToServer:(NSString *)address andUsername:(NSString *)username withPassword:(NSString *)password andInstallationId:(NSString*) installationId {
if (![self sendRequestToURL:address withMethod:@"POST" withUsername:username withPassword:password andInstallationId: installationId]) {
NSLog(@"Impossibile connettersi");
return NO;
} else {
if (authenticated) {
return YES;
} else {
return NO;
}
}
}
- (id)sendRequestToURL:(NSString *)url withMethod:(NSString *)method withUsername:(NSString*)username withPassword:(NSString*)password andInstallationId:(NSString*)installationId {
NSURL *finalURL = [[NSURL alloc]init];
if ([method isEqualToString:@"POST"]) {
finalURL = [NSURL URLWithString:url];
} else {
NSLog(@"Metodo no previsto");
}
NSString *post = [NSString stringWithFormat:@"username=%@&password=%@&installationId=%@", username, password, installationId];
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding];
NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)postData.length];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
[request setURL:finalURL];
[request setHTTPMethod:method];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
if (connection) {
[connection start];
}
return connection;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
self.responseData = [[NSMutableData alloc]init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Parsing della risposta dal server parlare con Giancarlo per vedere che tipo di risposta ottengo
NSDictionary *json;
NSError *err;
json = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:&err];
if (err) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"AT Brain" message:@"Impossibile satbilire una connessione con il server" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
} else {
NSString *error_code = [NSString stringWithFormat:@"%@", [json objectForKey:@"error_code"]];
int success = [[json objectForKey:@"success"] intValue];
NSString *error_desc = [NSString stringWithFormat:@"%@", [json objectForKey:@"error_desc"]];
if ([self autenthicationOkWithErrorCode:error_code withSuccess:success andErrorDesc:error_desc]) {
authenticated = YES;
} else {
authenticated = NO;
}
}
}
- (BOOL)autenthicationOkWithErrorCode:(NSString*)error_code withSuccess:(int)success andErrorDesc:(NSString*)error_desc {
int errCode = [error_code intValue];
if (success == 1) {
return YES;
} else if (success == 0) {
if (errCode == 2) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"AT Brain" message:@"Controlla di aver inserito username, password e di avere un installationId" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
return NO;
}
if (errCode == 3) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"AT Brain" message:@"Credenziali non valide, inserisci username e password corrette" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
return NO;
}
if (errCode == 4) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"AT Brain" message:@"Utente non autorizzato ad accedere al servizio" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
return NO;
}
if (errCode == 5) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"AT Brain" message:@"L'utenza a cui stai cercando di accedere è già associata ad un utente diverso" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
return NO;
}
if (errCode == 6) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"AT Brain" message:@"Installation ID errato" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
return NO;
}
}
return NO;
}
I can connect to the server without problem, but before the - (void)connectionDidFinishLoading:(NSURLConnection *)connection
is called it execute all the code in the - (BOOL)startConnectionToServer:(NSString *)address andUsername:(NSString *)username withPassword:(NSString *)password andInstallationId:(NSString*) installationId
and it returns NO so the segue in the login view controller doesn't work because the method -(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
returns NO.
So my problem is how to wait the execution of the method - (void)connectionDidFinishLoading:(NSURLConnection *)connection
is done before execute the else section in method - (BOOL)startConnectionToServer:(NSString *)address andUsername:(NSString *)username withPassword:(NSString *)password andInstallationId:(NSString*) installationId
?
I hope you understand my issue and I hope you will help me to fix it, thank you
Upvotes: 0
Views: 150
Reputation: 299345
NSURLConnection
is asynchronous. You kick it off and it immediately returns. You get callbacks (such as connectionDidFinishLoading
) when it completes. That's the point at which you can check for success and move onto the next step.
I assume that loginSuccessWith:and:
is called on the main thread (this is a very strange name for a method; you probably meant loginWithUsername:password:
). So it can't block waiting for a network request that may take a very long time to complete. You'd hang the entire UI.
The URL Loading System Programming Guide has a great deal of information on how to design this. Look first at NSURLSession
, and if it doesn't meet your needs, then use the lower-level NSURLConnection
. With NSURLSession
, you can pass completion blocks that will run whenever the operation completes.
Upvotes: 4