Bot
Bot

Reputation: 11865

Use MBProgressHUD with multiple dispatches

What is the best way get the label to change for HUD on both the processing thread and main thread?

[activitySpinner startAnimating];
    //[HUD setLabelText:@"Connecting"];
    //[HUD showUsingAnimation:YES];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
        hud.labelText = @"Connecting1";

        NSString *url = [NSString stringWithFormat:@"my URL", [dataObj.pListData objectForKey:@"API_BASE_URL"], userField.text, passwordField.text];
        NSLog(@"Login: %@",url);
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];

        NSError *error;        
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
        [HUD setLabelText:@"Processing"];
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([json objectForKey:@"authToken"] != nil) {
                [HUD setLabelText:@"Logging In"];
                NSLog(@"Found authtoken %@", [json objectForKey:@"authToken"]);
                [dataObj setAuthToken:[json objectForKey:@"authToken"]];
                [dataObj setLocationId:[json objectForKey:@"c_id"]];

                [dataObj setStaffId:[[json objectForKey:@"staffOrRoomsId"] integerValue]];
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                [HUD setLabelText:@"Downloading"];

                });

                [self getAllData];
                [self performSegueWithIdentifier:@"segueToRootController" sender:self];


            } else {
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:[json objectForKey:@"friendlyErrors"] delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
                [alert show];
                alert = nil;
            }
            [MBProgressHUD hideHUDForView:self.view animated:YES];
        });


        [activitySpinner stopAnimating];
    });

I've tried the above since if I run the label changing on the main thread it won't change until after all processing is done.

In my viewWillAppear I am setting

HUD = [[MBProgressHUD alloc] initWithView:self.view];
    [self.view addSubview:HUD];
    HUD.delegate = self;

It will show connecting but will not show Processing or downloading.

Upvotes: 2

Views: 1759

Answers (2)

Bot
Bot

Reputation: 11865

Actually after testing this on the device I found that it does indeed display Processing and Downloading. It just doesn't show it in the emulator. I guess since it uses the computer processor, it happens so quick.

Upvotes: 0

Matej Bukovinski
Matej Bukovinski

Reputation: 6152

Since Objective-C is case sensitive, you have two MBProgressHUD instances here:

  • HUD which you create with [[MBProgressHUD alloc] initWithView:self.view];, than add to the view, but fail to show (it's initially hidden)
  • hud which you create, add to the view and immediately show with the convenience constructor [MBProgressHUD showHUDAddedTo:self.view animated:YES];

This in essence means that HUD is hidden throughout your code and any property changes you set on it won't display (Processing and Downloading), while hud is visible and shows the only text you set on it (Connecting1).

There's an additional error in your code, and it involves creating a view (the hud MBProgressHUD instance) in a background thread. The general rule of thumb is to only modify views only in the main thread. Setting the hud's text (and some other properties) is one notable exception here, since MBProgressHUD does a bit of KVO trickery here in order to ensure thread safety for you.

In addition you should be aware that even when you fix the above error, you'll have a scenario where you set the text to "Logging In" (or display an alert) and immediately hide the HUD, which means that this text will be visible only very briefly. You probably wan't to hide the HUD when your download completes. There's also a similar issue with the activitySpinner.

All in all, you might try something like this (written from the top of my head):

[activitySpinner startAnimating];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = @"Connecting1";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSString *url = [NSString stringWithFormat:@"my URL", [dataObj.pListData objectForKey:@"API_BASE_URL"], userField.text, passwordField.text];
    NSLog(@"Login: %@",url);
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];

    NSError *error;        
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
    [hud setLabelText:@"Processing"];
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([json objectForKey:@"authToken"] != nil) {
            [hud setLabelText:@"Logging In"];
            NSLog(@"Found authtoken %@", [json objectForKey:@"authToken"]);
            [dataObj setAuthToken:[json objectForKey:@"authToken"]];
            [dataObj setLocationId:[json objectForKey:@"c_id"]];

            [dataObj setStaffId:[[json objectForKey:@"staffOrRoomsId"] integerValue]];
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                [HUD setLabelText:@"Downloading"];
                // Download synchronosly here? 
                dispatch_async(dispatch_get_main_queue(), ^{
                    [MBProgressHUD hideHUDForView:self.view animated:YES];
                    [activitySpinner stopAnimating];
                });
            });

            [self getAllData];
            [self performSegueWithIdentifier:@"segueToRootController" sender:self];
        } else {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:[json objectForKey:@"friendlyErrors"] delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
            [alert show];
            alert = nil;
            [MBProgressHUD hideHUDForView:self.view animated:YES];
            [activitySpinner stopAnimating];
        }
    });
});

Upvotes: 1

Related Questions