2010-06-30 111 views
1

我有一個自定義視圖控制器,實現從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

回答

3

需要在主線程上執行所有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