2013-01-15 62 views
3

我正在開發一個iOS應用程序,使用UITableView在某個階段添加或刪除一堆行。由於存在大量的行,因此此操作可能需要很長時間。但是,我不能輕易確定是否需要很長時間。長時間運行後延遲自旋活動指標

我想只顯示一個UIActivityIndi​​cator(微調),如果此操作需要很長時間。我一直這樣做的方式是開始冗長的操作,並經過一段時間(比如說0.5秒)後測試操作是否仍在運行,如果是,我們開始顯示UIActivityIndi​​cator。

如果你可以在後臺線程中運行冗長的操作,這是沒有問題的。然而,這種特殊情況很棘手,因爲冗長的操作(deleteRowsAtIndexPaths:withRowAnimation :)必須在主線程中運行(如果我在後臺線程中運行此方法,應用程序在後臺線程嘗試更新UI時偶爾崩潰)。

,我已經嘗試了最新的東西是這樣的線路:

- (void) manipulateTableView 
{ 
    stillBusy = YES; 
    [self performSelectorInBackground:@selector(waitBeforeShowingBusyIndicatorForView:) withObject:view]; 
    . 
    . 
    . 
    [self performSelectorOnMainThread:@selector(deleteRowsAtIndexPathsWithRowAnimation:) withObject:args waitUntilDone:YES]; 
    stillBusy = NO; 
} 

- (void) waitBeforeShowingBusyIndicatorForView:(UIView*) view 
{ 
    usleep((int) (BUSY_INDICATOR_DELAY * 1000000)); 
    if (stillBusy) 
     [self performSelectorOnMainThread:@selector(showBusyIndicatorForView:) withObject:view waitUntilDone:NO]; 
} 

因爲showBusyIndi​​catorForView:操縱UI,它必須在主線程中調用,否則應用程序可能會崩潰。

當deleteRowsAtIndexPaths:withRowAnimation:需要很長時間時,waitBeforeShowingBusyIndi​​catorForView中的延遲過期並調用performSelectorOnMainThread:...方法,並立即返回。但是接下來調用deleteRowsAtIndexPaths:withRowAnimation:完成後,showBusyIndi​​catorForView:方法僅調用,這違背了目的。

我想我明白爲什麼會發生這種情況。 deleteRowsAtIndexPaths:withRowAnimation:方法在主循環的迭代中運行,並且在運行時,showBusyIndi​​catorForView:的調用將作爲主循環的消息排隊。只有在主循環完成後才執行deleteRowsAtIndexPaths:withRowsAnimation:它輪詢隊列中的下一條消息,然後開始執行showBusyIndi​​catorForView :.

有什麼辦法讓這個東西正常工作。是否有可能中斷主循環,並立即執行showBusyIndi​​catorForView:

+0

你是針對ios6嗎? –

回答

0

Rob,感謝您的建議!它幫助我找到解決方案!

首先,爲了記錄,我只爲所有行調用了deleteRowsAtIndexPaths一次(其中有數千個:O!)。

我做的關鍵觀察是,當動畫開始時,只有少量的行在屏幕上可見。特別是該部分的頂部行,因爲刪除行是通過點擊該部分的標題觸發的。因此,行不一定都是動畫的一部分。我可以先刪除所有不可見的行(沒有動畫),然後用動畫刪除可見的行。

然後我有兩個調用deleteRowsAtIndexPaths - 第一個刪除所有不可見的行,第二個刪除可見(頂部)的行。現在,第一次調用deleteRowsAtIndexPaths需要很長時間,因爲它必須刪除數千行,並且活動指示器視圖再次沒有機會開始動畫。然後我改變了行去除的第一階段,以一個循環,在這樣的時刻取出的行200:

for (/* next range of invisible rows */) 
{ 
    // Compute index paths of the bottom 200 rows. 
    [self performSelectorOnMainThread:@selector(deleteRowsAtIndexPathsWithRowAnimation:) withObject:args waitUntilDone:YES]; 
} 

啓動該活動的指標動畫的方法,隨後將兩個後續呼叫之間進行排隊到deleteRowsAtIndexPaths ... :.

有趣的是:現在我一次只能移除200行,這需要相當長的時間,但它仍然比我一次全部移除它們快得多! :|

3

兩個選項在我撲過來:

  1. 修改你的長期運行的前臺程序,使其分解成多個數據塊,你多次單獨調度過程的每個步驟的主隊列。並以這種方式進行設計,以便設計進程,以便分派前臺慢任務的每個部分,並且只在前一部分完成時纔將下一步分派到主隊列。 (不要只爲主隊列排隊大量進程。)這樣,當微調隊員排隊時,你可以讓微調者有機會與其他工作銜接。如果你將缺失動畫化,這可能是不可能的,但是再次,我無法想象要花很長時間才能做出一個單一的deleteRowsAtIndexPaths

  2. 可能更好,如果更新花費了那麼長時間,我會問爲什麼。 deleteRowsAtIndexPaths不應該考慮到這一點。具體而言,不要發佈多個deleteRowsAtIndexPaths,而是要構建要刪除的行的NSMutableArray,然後在單個UI調用中刪除它們。我剛剛刪除了998行(包括它們的底層模型對象),並且幾乎是瞬間的。

如果可能的話,我會傾向於選項2。

0

在主線程上運行冗長的操作時,您無法更新UI。

如果你的延遲真的是由-deleteRowsAtIndexPaths:withRowAnimation:引起的(如果你要求表視圖動畫刪除幾千行的動畫效果非常好),那麼最好的解決方案是避免動畫超出特定的相對較小)的門檻,只需撥打-reloadData