2010-05-28 24 views
60

我正在研究一個iPhone應用程序,它具有一個非常大的UITableView與從網絡中獲取的數據,所以我試圖優化它的創建和使用。iPhone - dequeueReusableCellWithIdentifier用法

我發現dequeueReusableCellWithIdentifier非常有用,但是在看到很多使用這個源代碼的代碼之後,我想知道這個函數的用法是否合適。

這裏是人們通常做:

UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; 

if (cell == nil) { 
    cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"]; 

// Add elements to the cell 
return cell; 

這裏是我做的方式:

// The cell row 
NSString identifier = [NSString stringWithFormat:@"Cell %d", indexPath.row]; 

UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 

if (cell != nil) 
    return cell; 

cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:identifier]; 
// Add elements to the cell 
return cell; 

不同的是,人們使用相同標識符的每一個細胞,讓出列一個只能避免分配一個新的。

對我來說,排隊的重點是給每個單元格一個唯一的標識符,所以當應用程序要求已經顯示的單元格時,不需要添加分配和元素添加。

在精細我不知道這是最好的,「共同」的方法ceils表的內存使用細胞的確切數目也顯示,whislt我使用的方法似乎是因爲它使所有計算的青睞速度單元格,但會導致大量內存消耗(除非隊列中存在內部限制)。

我錯用這種方式嗎?還是取決於他的需求,它是否取決於開發者?

回答

70

dequeueReusableCellWithIdentifier的用途是使用較少的內存。如果屏幕可以放置4個或5個表格單元格,那麼即使表格有1000個條目,只需要在內存中分配4或5個表格單元格即可。

第二種方式沒有重用。第二種方法比使用表格單元格陣列沒有什麼優勢。如果你的表有1000個條目,那麼你將在內存中分配1000個單元。如果你打算這樣做,你可以把它們放在一個數組中,然後用行號索引數組並返回單元格。對於固定單元格的小型表格,這可能是一個合理的解決方案,對於動態或大型表格,這不是一個好主意。

+0

你說得對,用我的方法數組可以完成這項工作。 會有100個單元代表一次分配的「太多」大量內存嗎? – Jukurrpa 2010-05-28 13:03:56

+0

那麼,我改變了常見的方法(這是一個行有很多子視圖時很複雜),並且除了較低的內存消耗,滾動整體看起來更平滑,我不知道爲什麼。 感謝您的建議! – Jukurrpa 2010-05-28 14:40:18

+0

@progrmr ...謝謝...清理這個概念..它真的很好...我也在做同樣的錯誤.. :) – 2011-12-23 03:24:51

4

我認爲第一個是最好的(和你說的常見)的方式來實現UITableView。 隨着你的第二種方式,將爲每個顯示的新單元分配內存,並且不會重用內存。

+0

如果用戶向下滾動然後滾動回來,那麼會重新使用內存......或者任何時候tableView訪問一次顯示然後隱藏的單元格。 – Jukurrpa 2010-05-28 12:31:07

+0

當然,但是每個顯示的單元格都會有一個內存佔用區域,而不僅僅是當前顯示的4-5個單元格。 我對地圖的註釋有類似的問題。切換到恆定的標識符會顯着提高性能。 – AlexVogel 2010-05-28 12:34:18

+0

然後我想這取決於我......將緩存我用來創建單元格而不是單元格本身的任何數據會更好嗎? – Jukurrpa 2010-05-28 12:36:37

20

至於細胞標識符 - 而不是使用「細胞」作爲標識符,而不是使用像OP這樣的唯一標識符,你可以使用「類型標識符」嗎?例如,如果我的表格有3種類型的單元格 - 一種具有非常複雜的子佈局,一種只有Style1,另一種帶有Style2,我應該單獨標識這三種,然後在出現出現nil時重建它們。

例如:

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{ 
    NSString* ident = @""; 
    if(indexPath.section == 0) ident= @"complicated"; 
    if(indexPath.section == 1) ident= @"style1"; 
    if(indexPath.section == 2) ident = @"style2"; 

    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:ident]; 

    if(cell == nil){ 

     if(ident == @"complicated"){ 
      cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:ident] autorelease]; 
     // do excessive subview building 
     } 
     if(ident == @"style1"){ 
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyle1 reuseIdentifier:ident] autorelease]; 
     } 

     if(ident == @"style2"){ 
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyle2 reuseIdentifier:ident] autorelease]; 
     } 


    } 
    if(ident == @"complicated"){ 
     // change the text/etc (unique values) of our many subviews 
    } 
    if(ident == @"style1"){ 
     [[cell textLabel] setText:@"Whatever"]; 
    } 
    if(ident == @"style2"){ 
     [[cell textLabel] setText:@"Whateverelse"]; 
    } 

    return cell; 
} 

(此代碼可能不會運行,因爲我在這裏寫的,但希望你明白我的意思。)

我不認爲蘋果會創建整個可重複使用的單元格的想法與標識符,如果他們想要所有的標識符是"cell",你不覺得嗎?

+0

在你的情況下,我會爲每個單元佈局使用一個標識符。這意味着一個用於「複雜」的單元格,一個用於「style1」單元格,另一個用於style2單元格,如果他們的子視圖與style1單元格不同。 在dequeue返回nil的情況下,添加帶有標籤的單元格子視圖(在枚舉或其他東西中定義),然後初始化它們。在dequeue返回一個單元格的情況下,只需使用標籤檢索子視圖並更改它們即可。 分隔你的代碼在每個部分的一種方法將不錯:) – Jukurrpa 2010-06-09 22:56:14

+0

這是一個很好的答案。我投了票。 – 2014-12-01 03:24:59

13

幫助我理解爲什麼慣用方式(首先描述的方法)效果最好的文檔是UITableViewCell class reference關於initWithStyle:reuseIdentifier:方法的部分。

reuseIdentifier款曰:

你應該使用相同的重用標識符相同形式的所有細胞。

而「討論」小節讀取:

重用標識符與具有相同的一般結構的表格視圖的那些細胞(行),減去細胞內容相關聯。

這些陳述清楚地告訴我說,慣用的方式來使用你的dequeueReusableCellWithIdentifier實施tableView:cellForRowAtIndexPath:內的不管可用行的總數您UITableViewDataSource會爲每個可見行的一個單元對象。

1

UITableView內部使用帶標識符的單元格作爲「模板」。所以下一次你(以表格的形式閱讀)嘗試使用deque時,它只是創建一個新的單元格,但使用存儲的對象作爲模板。因此,你仍然需要更新它的用戶界面以反映每個上下文的單元格內容。

這也意味着UITableView正在爲我們自己做單元的內存管理。從理論上講,只有很多可見光單元的物體。但實際上,可能會有更多的內存等待發布。

這基本上可以節省內存很大的時間,特別是在有1000個單元的情況下。

在任何內存非常重要的便攜式設備上,我們應該將任何內存的分配推遲到最後一刻,並在其作業完成後立即釋放內存。 dequeAndReusing一個細胞實現這一點,並做得很好。另一方面,如果你的單元格是一個自定義的單元格,那麼我們可能最有可能加載一個筆尖並從中提取它。 如果是這種情況,您可以使用標識符來取消或者您可以從筆尖加載它。程序中沒有區別。

唯一的區別可能是加載時間。允許使用表格視圖創建一個使用標識符單元格作爲模板的新單元格可能比從nib加載稍快,但幾乎不明顯,取決於上下文。

+0

自定義單元格也由tableView的內存隊列系統管理,只要它們具有「標識符」集。 – Tim 2011-12-03 23:03:16

0

要區分單元格與其他單元格,您可以使用單元格的標籤屬性,或者如果您使用的是自定義單元格,那麼通過將任何新屬性引入自定義單元格同時子類化UITableViewCell非常容易。

即使畢竟這些你被卡住,仍然需要得到的細胞,那麼你可以嘗試下面的代碼

UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath]

,而應該避免高達程度,因爲它產生細胞的複製,但做不返回現有的單元格,而內​​容將具有相同的值。

相關問題