2009-07-25 101 views
7

我正在修改一些現有的笨拙代碼,只需簡單地調用[tableView reloadData]就可以對任何更改使用更具體的表格更新與插入/刪除方法。UITableView insertSections:withRowAnimation:導致請求所有表格單元格

但是,我得到這樣做有一些非常糟糕的行爲。以前,正如人們所想象的那樣,當表格加載時,它只會請求單元格用於當時可見的行。這是使用reloadData時的行爲。

現在insertSections被調用,全部該更新後,請求單元格,可能是數百。這會導致爲每一行創建單元格,從而徹底破壞可重用的單元隊列,並造成浪費。我必須做錯了什麼。

的變化是這樣的簡單,代碼導致的tableView要求僅適用於可見行:

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context { 
    // ... ensure it's the right key 
    NSUInteger sectionCount = [self sectionCount]; 
    NSIndexSet *indices = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)]; 
    [tableView insertSections:indices withRowAnimation:UITableViewRowAnimationFade]; 
} 

我可以切換回:那導致的tableView要求一切

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context { 
    // ... ensure it's the right key 
    [tableView reloadData]; 
} 

代碼並且看到行爲改變。令人沮喪。想法?


添加賞金只是爲了看看有沒有人有更多的見解。

的beginUpdates/endUpdates不會影響任何東西,我不希望它來,這只是一個命令,沒有什麼額外的凝聚成一個單一的更新。

我想這僅僅是希望動畫的副作用。爲了讓所有內容「滑動」,它必須呈現一切。遊戲結束。

+0

你是怎麼確定所有的單元格一次都被請求的?沒有人出列? – Pascal 2009-10-27 15:15:10

+0

我創建了一個小型測試項目,可以重現您正在觀察的行爲。它真的很好奇。如果您指定了UITableViewRowAnimationNone,則行爲是相同的,因此不能僅僅是動畫。 如果insertSections:withRowAnimation:被調用時插入位置不在屏幕上,則不會發生此問題。 – 2009-10-27 22:15:52

回答

6

看樣子你是在告訴表中插入所有的部分,這基本上等同於一個重載的。當你告訴表格需要加載一個部分時,它需要讀取該部分中的所有項目。此外,您正在執行beginUpdates/endUpdates塊以外的任務,這意味着每次添加表時必須立即提交更改。如果將所有內容都包含在beginUpdates/endUpdates中,它將掛起所有查詢,直到完成,這將允許系統合併冗餘查詢並消除不必要的查詢。

你應該只調用與添加了新的章節insertSections。如果你這樣做,那麼tableview不必查詢所有未改變的部分的信息,即使他們四處移動。此外,如果段內的元素髮生更改,但段本身不發生變化,則應使用行版本的方法修改段內的特定行,並僅查詢那些行。

下面是一個應該得到跨越點的例子(從基於CoreData的應用程序)。既然你有一個自定義的模型,而不是一個NSFetchedResultsController,你將不得不找出正在進行的動作的類型,而不是僅僅檢查系統交給你的一堆常量。

//Calculate what needs to be changed  

[self.tableView beginUpdates]; 

for (i = 0 i < changeCount; i++) { 
    type = changes[i]; 

    switch(type) { 
    case NSFetchedResultsChangeInsert: 
     [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] 
        withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeDelete: 
     [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] 
        withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
    } 
} 

switch(type) { 

    case NSFetchedResultsChangeInsert: 
    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
    break; 

    case NSFetchedResultsChangeDelete: 
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
    break; 

    case NSFetchedResultsChangeUpdate: 
    [self configureCell:(id)[tableView cellForRowAtIndexPath:indexPath] 
      atIndexPath:indexPath]; 
    break; 

    case NSFetchedResultsChangeMove: 
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] 
        withRowAnimation:UITableViewRowAnimationFade]; 
    break; 
    } 
} 

[self.tableView endUpdates]; 
+0

那麼,在一點額外的信息可能是有用的,這是一個完全空表最初。爲了保持用戶界面的響應,我推遲了加載數據的方式,所以它最初會出現空白,並且會在它們進入網絡時添加這些部分。因此,從沒有節到使用reloadData的所有節都可以正常工作,但是顯式添加節導致混亂?奇怪的。 – 2009-07-25 18:13:25

+0

不,這是預期的,爲什麼你需要beginUpdates/endUpdates調用來包裝你正在做的事情。如果沒有這些,tableView必須假設每次修改後都會影響顯示,這意味着它必須查詢所有部分以計算可見的單元格,然後獲取所有可見的單元格。當您執行beginUpdates時,tableView將停止更新,直到您調用endUpdates,此時它可以一次性查詢所有中間狀態。 「 – 2009-07-25 23:01:07

+0

」而不詢問您的中介國家,「我需要更多咖啡 – 2009-07-25 23:02:49