Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow User to Cancel MBProgressHUD when JSON call takes too long

I've read and read on SO about this, and I just can't seem to find anything that matches my situation.

I've got MBProgressHUD loading when the view appears, as my app immediately goes to grab some webservice data. My problem is the back button on my navigationcontroller is unresponsive while the HUD is displayed (and therefore while the app gets its data). I want the user to be able to tap to dismiss (or to be able to hit the back button in the worst case) to get the heck out, if it's an endless wait. Here's my code that runs as soon as the view appears:

#ifdef __BLOCKS__
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.labelText = @"Loading";
hud.dimBackground = NO;
hud.userInteractionEnabled = YES;

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    // Do a task in the background
    NSString *strURL = @"http://WEBSERVICE_URL_HERE";

    //All the usual stuff to get the data from the service in here

    NSDictionary* responseDict = [json objectForKey:@"data"]; // Get the dictionary
    NSArray* resultsArray = [responseDict objectForKey:@"key"]; 


    // Hide the HUD in the main tread
    dispatch_async(dispatch_get_main_queue(), ^{

        for (NSDictionary* internalDict in resultsArray) 
        {
            for (NSString *key in [internalDict allKeys]) 
            {//Parse everything and display the results
            }

        }

        [MBProgressHUD hideHUDForView:self.navigationController.view animated:YES];
    });
}); 
#endif

Leaving out all the gibberish about parsing the JSON. This all works fine, and the HUD dismisses after the data shows up and gets displayed. How in the world can I enable a way to stop all this on a tap and get back to the (blank) interface? GestureRecognizer? Would I set that up in the MBProgressHUD class? So frustrated...

Kindest thanks for any help. My apologies for the long post. And for my ugly code...

like image 564
gummo Avatar asked Nov 03 '12 19:11

gummo


2 Answers

No need to extend MBProgressHUD. Simply add an UITapGestureRecognizer to it.

ViewDidLoad :

MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:NO];
HUD.mode = MBProgressHUDModeAnnularDeterminate;

UITapGestureRecognizer *HUDSingleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(singleTap:)];
[HUD addGestureRecognizer:HUDSingleTap];

And then:

-(void)singleTap:(UITapGestureRecognizer*)sender
{
      //do what you need.
}
like image 85
Piotr Tomasik Avatar answered Nov 11 '22 05:11

Piotr Tomasik


The MBProgressHUD is just a view with a custom drawing to indicate the current progress, which means it is not responsible for any of your app's logic. If you have a long running operation which needs to be canceled at some point, you have to implement this yourself.

The most elegant solution is to extend the MBProgressHUD. You can either draw a custom area which plays the role of a button, add a button programmatically or just wait for a tap event on the whole view. Then you can call a delegate method whenever that button or the view is tapped.

It can look like this:

 // MBProgressHUD.h
 @protocol MBProgressHUDDelegate <NSObject>
 - (void)hudViewWasTapped; // or any other name 
 @end

// MBProgressHUD.m
// Either this, or some selector you set up for a gesture recognizer
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([self.delegate respondsToSelector:@selector(hudViewWasTapped)]) {
        [self.delegate performSelector:@selector(hudViewWasTapped)];
    }
}

you have to set your view controller as the delegate for theMBProgressHUD and act accordingly.

Let me know if you need more clarification on this :)

like image 43
iska Avatar answered Nov 11 '22 05:11

iska