views:

233

answers:

1

I have a custom view controller that implements the from UITableViewDataSource and UITableViewDelegate protocols. When I load data for my table (in my viewDidLoad method), I create a NSOperationQueue and a NSInvocationOperation and add it to the queue. I throw up an activity indicator, and viewDidLoad exits.

The method used for the operation ends the activity indicator animation.

I have noticed that when the operation completes, there is a 5-7 second pause before the operation really completes, even though by NSLog it looks like the operation's method returned.

I have tried to use Instruments to figure out where the pause is happening, but I can't tell from it because most of my CPU time is spent in system libraries.

Edit Here's an abbreviated version:

@implementation MyViewController
@synthesize ...

- (void)viewDidLoad {
    [super viewDidLoad];
    self.opsQueue = [[NSOperationQueue alloc] init];

    NSInvocationOperation *aiStartOp = [[[NSInvocationOperation alloc]
                                           initWithTarget:self
                                                 selector:@selector(showActivityIndicators)
                                                   object:nil] autorelease];
    [self.opsQueue addOperation:aiStartOp];

    NSInvocationOperation *dataOp = [[[[NSInvicationOperation alloc] 
                                         initWithTarget:self
                                               selector:@selector(dataUpdate)
                                                 object:nil] autorelease];
    [dataOp addDependency aiStartOp];
    [self.opsQueue addOperation:dataOp];

    NSInvicationOperation *aiStopOp = [[[NSInvicationOperation alloc]
                                          initWithTarget:self
                                                selector:@selector(hideActivityIndicators)
                                                  object:nil] autorelease];
    [aiStopOp addDependency:dataOp];
    [self.opsQueue addOperation:aiStopOp];
}

/* other stuff */

@end

Just to be clear, the last operation in the queue is this:

- (void)hideActivityIndicators {
    DLog(@"hiding activity indicator");
    self.portraitChartProgressView.hidden = YES;
    [self.portraitChartProgressIndicator stopAnimating];

    self.landscapeProgressView.hidden = NO;
    [self.landscapeProgressIndicator startAnimating];
}

What I see in the log is the output of the above log message, followed by a pause of 5 seconds, and then finally followed by the view with the indicator on it being hidden.

Any ideas?

+2  A: 

All UI events, drawing etc. need to be performed on the main thread. You can forward calls to the main thread using something like the following.

- (void)hideActivityIndicators {

    if (![NSThread isMainThread]) 
         [self performSelectorOnMainThread:@selector(hideActivityIndicators) withObject:nil waitUntilDone:NO];

    DLog(@"hiding activity indicator");
    self.portraitChartProgressView.hidden = YES;
    [self.portraitChartProgressIndicator stopAnimating];

    self.landscapeProgressView.hidden = NO;
    [self.landscapeProgressIndicator startAnimating];
}

EDIT"

Now that I look a little more carefully, one thing you probably don't need to do is start and stop the "loading" views by adding to an NSOperationQueue. Likely the only thing that you need to do in in the queue is the data update, then post notifications and delegation to update your views when the data operation is complete.

The TopSongs sample project demonstrates this very well. The forwarding statement to the main thread is based on code in the AppDelegate.m file in the sample.

falconcreek
Yes, that was the issue all right. I'm now curious, though: if all UI updates should be performed on the main thread, why don't they just throw an exception? Why are they executed as expected, but simply delayed by 5 s?
Ben Collins
Basically, the views were not being redrawn to match the state changes performed on the view objects from the other thread until after the run loop for the other thread was torn down. Not an exception, but a concurrency problem. More details here http://developer.apple.com/iphone/library/documentation/cocoa/conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
falconcreek