UIAlertview hanging while the thread in background

2019-06-11 09:50发布

I have a UIBarButtonItem called "Refresh Data". When user clicks it, the app should refresh its data. What happens on that button click is web services are launched and xml data is brought and they are of the order 30000-40000 records. So to prevent UI from hanging i wrote a background thread and did that loading there.

- (void)refreshDataAction
{
NSLog(@"Refresh Data");
//Put up an alert box indicating user to wait while data is loading.

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Data is Loading"
                                                        message:@"Please wait while data is being refreshed."
                                                       delegate:self
                                              cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil, nil];
alert.tag = 10;
[alert show];
 }

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(@"hit in clickedbuttonatindex alertview at 259");
self.refreshActIndicator.hidden = NO;
[self.refreshActIndicator startAnimating];
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                         (unsigned long)NULL), ^(void) {
    [self getAllCustomerValues];

    NSError *nwerror = nil;
    if (![self.secondMOC save:&nwerror])
    {
        NSLog(@"209 Failed to save second MOC");
    }
    else
    {
        //NSLog(@"saved success");
    }
 });
}

Like you can see alert view shows up. I click OK and the box is still there its "blackened" and its hanging there on the screen. And then 7-8 seconds later the box disappears and the animation starts for activity indicator. My goal is to get something like this. 1.User clicks on the refresh data button. 2.Alert view shows up. 3.User clicks OK. 4.Alert box disappears and immediately the background thread starts working and i see the activity indicator working/animating.

User will know to wait while the activity indicator is animating. So how do i get the app to start animating immediately after user clicks "OK" and the alertview OK not be blackened. Am i clear?If you need more information, please ask. Thanks

EDIT: This screen has a background thread working on it when it loads the first time for that day. There is a screen before this. On it i have continue button and clicking that launches background thread which does exactly the same thing like this one over here.I dont kill it or anything.

EDIT 2:

 - (void)refreshDataAction
   {
NSLog(@"Refresh Data");
self.txtCustomerSearch.text =@"";
[self cleanUPPreviousLabels];

//Put up an alert box indicating user to wait while data is loading.

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Data is Loading"
                                                message:@"Please wait while data is being refreshed."
                                               delegate:self
                                      cancelButtonTitle:@"OK"
                                      otherButtonTitles:nil, nil];
//alert.tag = 10;
//[alert show];
[alert performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:FALSE];

NSLog(@"hit in willpresenet alertview at 221");
    self.refreshActIndicator.hidden = NO;
    [self.refreshActIndicator startAnimating];
NSLog(@"Dispatching");

//Disable the view and all the other controls
self.txtCustomerSearch.userInteractionEnabled =NO;
self.txtCustomerSearch.enabled =NO;
self.btnSearch.enabled =NO;
self.btnSearch.userInteractionEnabled = NO;
self.scrollView.userInteractionEnabled = NO;
//self.view.userInteractionEnabled =NO;
self.chkButton.enabled = NO;


[self deletePreviousValues]; 

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSLog(@"Getting customer values");
    [self getAllCustomerValues];
    NSLog(@"Got customer values");

    NSError *nwerror = nil;
    if (![self.secondMOC save:&nwerror])
    {
        NSLog(@"209 Failed to save second MOC");
    }
    else
    {
        //NSLog(@"saved success");
    }


    self.txtCustomerSearch.userInteractionEnabled = YES;
    self.txtCustomerSearch.enabled =YES;
    self.btnSearch.enabled =YES;
    self.btnSearch.userInteractionEnabled = YES;
    self.scrollView.userInteractionEnabled = YES;
    self.view.userInteractionEnabled =YES;
    self.chkButton.enabled = YES;

    [self.refreshActIndicator stopAnimating];

    NSLog(@"Saved");


});
NSLog(@"Dispatched");

}

5条回答
forever°为你锁心
2楼-- · 2019-06-11 10:16

We using MBProgressHUD (https://github.com/jdg/MBProgressHUD) which makes this kind of UI notification easy. Generally you supply a method to be called that can check an atomic BOOL value. Set the BOOL when you put up the HUD, when the background process is complete clear the BOOL and the HUD will automatically go away.

查看更多
姐就是有狂的资本
3楼-- · 2019-06-11 10:22

Use alertView:didDismissWithButtonIndex: instead of alertView:clickedButtonAtIndex:. This way the alert is already dismissed when your code is called.

Question - why bother with the alert view? The user knows they tapped a "refresh" icon. You already show an activity indicator, and the alert doesn't give the user a chance to cancel the refresh.

Update: The call to dispatch_async seems a bit off. Try this:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self getAllCustomerValues];

    NSError *nwerror = nil;
    if (![self.secondMOC save:&nwerror]) {
        NSLog(@"209 Failed to save second MOC");
    } else {
        //NSLog(@"saved success");
    }
});
查看更多
做个烂人
4楼-- · 2019-06-11 10:31

Try changing

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                     (unsigned long)NULL), ^(void) {

to the background priority

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
                                     (unsigned long)NULL), ^(void) {
查看更多
Bombasti
5楼-- · 2019-06-11 10:32

It might help to add some NSLogs to see where it is hanging and stop the activity indicator to see if the entire hang happens because of the dispatch.

 NSLog(@"hit in clickedbuttonatindex alertview at 259");
 self.refreshActIndicator.hidden = NO;
 [self.refreshActIndicator startAnimating];
 NSLog(@"Dispatching");
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                     (unsigned long)NULL), ^(void) {
    NSLog(@"Getting customer values");
    [self getAllCustomerValues];
    NSLog(@"Got customer values");

    NSError *nwerror = nil;
    if (![self.secondMOC save:&nwerror])
    {
        NSLog(@"209 Failed to save second MOC");
    }
    else
    {
        //NSLog(@"saved success");
    }
    [self.refreshActIndicator stopAnimating];
    NSLog(@"Saved");
 });
 NSLog(@"Dispatched");

What is happening is that the main (UI) queue is being stopped for some reason, which causes things to appear to hang. Because it is stopped, things like refresh activity indicators will not animate even if you have told them to start animating. And remember that you cannot update the UI in async so secondMOC should not be used to cause any tables to reload data and [self getAllCustomerValues]; should not do any UI stuff.

查看更多
兄弟一词,经得起流年.
6楼-- · 2019-06-11 10:34

You say this is all happening on a background thread - make sure you load the UIAlertView on the main thread:

//[alert show];
[alert performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:FALSE];

This will probably fix the problem. Your async call is actually happening on the current thread in the run loop (since it's a background thread), blocking the alert view you're attempting to display (in the same run loop).

查看更多
登录 后发表回答