Question

I have an app that makes web service calls to obtain data. I want to add an activity indicator that is visible when the app is fetching web service data. I have looked into other posts, and though I believe I am doing as the posts recommend, my indicator does not render on the screen. The object that makes the web service call is stateGauges. Here is my code:

- (void)viewDidLoad
{
    [super viewDidLoad];
    UIActivityIndicatorView *activityStatus = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(120, 230, 50, 50)];
    activityStatus.center = self.view.center;
    [self.view addSubview:activityStatus];
    [activityStatus bringSubviewToFront:self.view];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;

    [activityStatus startAnimating];
    stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
    [activityStatus stopAnimating];
}

Any suggestions? Thanks! V

Was it helpful?

Solution

Your problem is that your animation start is blocked by whatever you're doing in your GuagesList initializer.

When you tell the activity indicator to start animating, it doesn't immediately render to the screen but rather flags the view as needing an update on the next turn of the run loop. Your initializer then blocks the thread until its done, you call stopAnimating, and then the thread has a chance to update the indicator. By which point its already set to not animate.

The best solution is to perform your initializer on another thread using GCD. And be sure to switch back to the foreground thread before calling stopAnimating.

The usual pattern is do something like:

[activityStatus startAnimating];
// enqueue it
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
    // now switch back to main thread
   dispatch_async(dispatch_get_main_queue(), ^{
      [activityStatus stopAnimating];         
   });
});

You'll want to verify the code as I had to type this from memory on a Windows machine.

OTHER TIPS

take out

[activityStatus bringSubviewToFront:self.view];

because according to the docs bringSubviewToFront:

Moves the specified subview so that it appears on top of its siblings.

which isn't what you want. (another answer suggested you do [self.view bringSubviewToFront:activityStatus] instead.. that's fine, but generally this call is redundant, b/c [self.view addSubview:activityStatus] adds the activityStatus to the end of the views in the self.view subviews array anyways)

if that still don't work.. basically put a break point right after you start animating, then type this into the console:

[[activityStatus superview] recursiveDescription]

recursiveDescription will give you a UI tree graph and basically tell you exactly where the activityIndicator view is.. you may have made an incorrect assumption about something.

Change

[activityStatus bringSubviewToFront:self.view];

To

[self.view bringSubviewToFront:activityStatus];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top