Question

Here is my code...

- (void) threadStartAnimating {
    [activityIndicator startAnimating];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    activityIndicator=[[UIActivityIndicatorView alloc] init];
    [activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
    activityIndicator.center=[self tableView].center;
    [[self tableView] addSubview:activityIndicator];

    [NSThread detachNewThreadSelector:@selector(threadStartAnimating) toTarget:self withObject:nil];
    EventController *eventController = [[EventController alloc] init];
    [eventController setEventID:[[lineItems objectAtIndex:[indexPath row]] objectForKey:@"view_event_button_param"]];
    [activityIndicator stopAnimating];
    [[self navigationController] pushViewController:eventController animated:YES];
}

The event controller contains a web service that takes a few seconds to load. The only way I can get the activity indicator to show is if I throw an infinite loop in there... I found a bunch of examples that mentioned putting it in a separate thread but it doesn't seem to work.

Was it helpful?

Solution

Your problem is that if you're getting the data in viewDidLoad then that method won't be called until after the view is loaded, which is usually during the process of first displaying that view controller. In your case this is during the pushViewController:animated: call.

So one way to do what you want might be to swap around these two lines:

[activityIndicator stopAnimating];
[[self navigationController] pushViewController:eventController animated:YES];

But, in all honesty, I would create a protocol called EventControllerDelegate, have a weak reference property to an id <EventControllerDelegate> in your EventController and then set the view controller which creates the EventController as the delegate before you push it. Then define a method in the delegate and implement it in your view controller and in that method stop the spinner. Then in EventController, when you've finished loading your data, call the delegate method.

Edit: If you really want to do it without defining a delegate, you could try changing your code to something like this:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    activityIndicator=[[UIActivityIndicatorView alloc] init];
    [activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
    activityIndicator.center=[self tableView].center;
    [[self tableView] addSubview:activityIndicator];

    EventController *eventController = [[EventController alloc] init];
    [eventController setEventID:[[lineItems objectAtIndex:[indexPath row]] objectForKey:@"view_event_button_param"]];

    [activityIndicator startAnimating];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        UIView *v = eventController.view;

        dispatch_async(dispatch_get_main_queue(), ^{
            [activityIndicator stopAnimating];
            [[self navigationController] pushViewController:eventController animated:YES];
        });
    });
}

It's using GCD for clarity and the usual "access the view property to force a loadView / viewDidLoad" hack.

OTHER TIPS

You need to set a frame size for your activityIndicator.

activityIndicator.frame = CGRectMake(x, y, 40, 40);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top