NSOperationQueue似乎挂起完成几秒钟

问题描述:

我有一个自定义视图控制器,实现从UITableViewDataSourceUITableViewDelegate协议。当我加载我的表的数据时(在我的viewDidLoad方法中),我创建了一个NSOperationQueue和一个NSInvocationOperation并将其添加到队列中。我抛出一个活动指示器,并退出viewDidLoadNSOperationQueue似乎挂起完成几秒钟

用于该操作的方法结束活动指示器动画。

我注意到,当操作完成时,在操作真正完成之前有5-7秒的暂停,即使通过NSLog它看起来像操作的方法返回。

我试图用仪器找出停顿在哪里,但是我无法从中发现,因为我的大部分CPU时间都花在系统库中。

编辑 下面是一个简化版本:

@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 

只要是明确的,在队列中的最后一个操作是这样的:

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

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

我在日志中看到的是输出上面的日志消息,然后是5秒的暂停,然后最后是隐藏指示器的视图。

任何想法?

+0

您是否在主线程上调用hideActivityIndi​​cators? – falconcreek 2010-06-30 18:33:59

+0

@falconcreek:no;我是不是该? (请参阅编辑以更好地了解正在发生的事情) – 2010-06-30 18:39:52

需要在主线程上执行所有UI事件,绘图等。 您可以使用类似于以下内容的方式将呼叫转接到主线程。

- (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”

现在我看起来更仔细,有一件事你可能并不需要做的是启动和停止‘加入到NSOperationQueue装载’的意见。可能的在队列中唯一需要做的就是数据更新,然后发布通知和委托以在数据操作完成时更新视图。

示例项目TopSongs演示了这一点。主线程基于c在示例中的AppDelegate.m文件中。

+0

是的,那是问题所在。但我现在好奇:如果所有UI更新都应该在主线程上执行,为什么他们不会抛出异常呢?他们为什么按预期执行,但只是延迟了5秒? – 2010-06-30 19:52:09

+0

基本上,视图没有被重绘,以匹配从其他线程的视图对象上执行的状态更改,直到其他线程的运行循环被拆除。不是一个例外,而是一个并发问题。更多细节在这里http://developer.apple.com/iphone/library/documentation/cocoa/conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html – falconcreek 2010-06-30 20:08:04

+0

谢谢,它帮助我解决了类似的问题。 – negersiu 2010-11-25 14:12:19