Question

I'm currently working on an app that uses a basic login page to check if the user has access to the app. I've made the login part with help of this tutorial which uses this frame work to use username and password from a simple web script.

I'm hoping that someone else maybe have worked with it or can help me with my issue. I wan't to show an activity indicator, I'm using MBProgressHUD as an activity indicator.

So I've experimented with it but can't get it to show the activity indicator when the app is connecting to the URL. I've done some bad connection simulating with the login process but the activity indicator won't show up when the app is connecting to the URL. It only shows on errors and the only thing that shows any kind of loading on success is that the login buttons pressed state is "active" (blue highlighted) until the loading is done.

So here's my code that runs when the user has typed in username and password and clicks on the login button:

// Login button
- (IBAction)loginBtnClicked:(id)sender
{
    // Show the activity indicator
    [HUD showUIBlockingIndicatorWithText:@"Loggar in..."];

    @try {
        if([[userNameTxtField text] isEqualToString:@""] || [[passwordTxtField text] isEqualToString:@""] ) {

            // No username or password entered
            [self alertStatus:@"Du måste ange användarnamn och lösenord" :@"Något gick fel!"];

            // Hide activity indicator
            [HUD hideUIBlockingIndicator];

        } else {

            NSString *post =[[NSString alloc] initWithFormat:@"username=%@&password=%@",[userNameTxtField text],[passwordTxtField text]];
            NSLog(@"PostData: %@",post);

            NSURL *url=[NSURL URLWithString:@"http://www.nebulon.se/json/sendus/jsonlogin.php"];

            NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

            NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

            NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
            [request setURL:url];
            [request setHTTPMethod:@"POST"];
            [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
            [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
            [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
            [request setHTTPBody:postData];

            //[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];

            NSError *error = [[NSError alloc] init];
            NSHTTPURLResponse *response = nil;
            NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

            NSLog(@"Response code: %d", [response statusCode]);
            if ([response statusCode] >=200 && [response statusCode] <300){

                NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
                NSLog(@"Response ==> %@", responseData);

                SBJsonParser *jsonParser = [SBJsonParser new];
                NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
                NSLog(@"%@",jsonData);
                NSInteger success = [(NSNumber *) [jsonData objectForKey:@"success"] integerValue];
                NSLog(@"%d",success);

                if(success == 1){

                    // Login success, grant user access to app
                    NSLog(@"Login SUCCESS");

                    [self loginSuccess];

                    // Hide activity indicator
                    [HUD hideUIBlockingIndicator];

                    // Store username
                    NSString *userName = [userNameTxtField text];
                    NSUserDefaults *UserDefaults = [NSUserDefaults standardUserDefaults];
                    [UserDefaults setObject:userName forKey:@"userName"];
                    [UserDefaults synchronize];

                    [self dismissViewControllerAnimated:NO completion:nil];

                } else {

                    // Login error
                    NSString *error_msg = (NSString *) [jsonData objectForKey:@"error_message"];
                    [self alertStatus:error_msg :@"Inloggningen misslyckades"];
                    [self loginFailed];

                    // Hide activity indicator
                    [HUD hideUIBlockingIndicator];
                }

            } else {

                // Login error
                if (error) NSLog(@"Error: %@", error);
                [self alertStatus:@"Ingen nätverksuppkoppling hittades." :@"Ett fel har inträffat!"];
                [self loginFailed];

                // Hide activity indicator
                [HUD hideUIBlockingIndicator];
            }
        }
    }
    @catch (NSException * e) {

        // Login error
        NSLog(@"Exception: %@", e);
        [self alertStatus:@"Inloggningen misslyckades." :@"Ett fel har inträffat!"];
        [self loginFailed];

        // Hide activity indicator
        [HUD hideUIBlockingIndicator];
    }
}
Was it helpful?

Solution

I believe the issue is due to the use of sendSynchronousRequest:returningResponse:error:

This method will be blocking the main/UI thread so the HUD never actually gets a chance to show until the method has returned, at which point the code continues and the HUD is hidden.

I think you should be looking at using an asynchronous request. and implementing the NSURLConnection delegate methods.

EDIT: Added code sample.

Assuming you're targeting iOS 5 and higher you can use the following code snippet which takes advantage of blocks with sendAsynchronousRequest:queue:completionHandler: and GCD.

NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:backgroundQueue
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

                           // NOTE: This block is called on the background queue.

                           // Use GCD to get back onto the main thread
                           dispatch_async(dispatch_get_main_queue(), ^{
                               // This block will process the response and data on the main thread
                           });

                       }];

It really is very little work to port your existing code to use this mechanism. If you don't know how blocks work you should read the documentation as they are a very powerful language feature and are being used in an increasing amount of Apple and third-party frameworks.

I would also recommend staying AWAY from third-party networking libraries for now until you understand the nuances that can cause issues such as this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top