2015-11-01 79 views
1

我有一個UITableview,它有一些歷史記錄。我使用自定義單元來處理標籤,圖像和按鈕的顯示。 UITableview內有大約50行。但問題是當Tableview向上滾動時,那麼在第一個顯示的下面的行中已經改變了它的值。不確定Tableview究竟發生了什麼。當UITableview向上或向下滾動時值發生了變化

static NSString *CellIdentifier = @"HistoryCell"; 
cellHistory = [self.notificationTableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 

[cellHistory.label clearActionDictionary]; 
//Step 2: Define a selection handler block 
void(^handler)(FRHyperLabel *label, NSString *substring) = ^(FRHyperLabel *label, NSString *substring) 
{ 
    [self userNameTapped:[[[[self.arrayHistory objectAtIndex:indexPath.row] objectForKey:Details] objectForKey:@"key"] objectForKey:@"key"]]; 
}; 

//Step 3: Add link substrings 
[cellHistory.label setLinksForSubstrings:@[userName] withLinkHandler:handler]; 
return cellHistory; 
+0

請提供更多代碼,如何將數據設置到您的單元格中。 –

+0

我已經更新了上面的代碼。 – Nishan29

+1

您的細胞正在被重複使用。基本的iOS設計知識。大量的例子在線 – soulshined

回答

8

謹防

以下的答案必須解決的具體實施,而不是設計。使用NSFetchedResultsController的樣板代碼將首先防止此錯誤發生。 (Apple documentation)。不惜一切代價,避免操縱一旦通過cellForRowAtIndexPath返回的單元格:你做不是擁有它。


1.重複使用的細胞不會被緩存

中特別令人擔憂的是這一行:

[self.arrayHistory objectAtIndex:indexPath.row] 

與其說是因爲該特定實例的,而是因爲它使我認爲你在這個課程的其他地方做假設:通過dequeueReusableCellWithIdentifier檢索的UITableViewCell不過是一個瞬態對象,純粹用於UITableView顯示。

的非常相同的小區的實例將具有多個indexPath隨時間:這樣的細胞可能不被緩存或在進一步的日期操縱。一旦作爲cellForRowAtIndexPath的最後一條語句返回,可能會再次訪問而不是,無論是通過某種外部指針通過某種異步方法保留。始終將通過dequeueReusableCellWithIdentifier獲取的緩存表視圖的索引路徑視爲陳舊

不是修改一次返回的單元格的內容。按照以下Losiowaty所述的正確設計。

對於更好的判斷,如果您必須修改已經返回到表視圖的單元格的內容,那麼您必須爲此使用一個持久單元格,例如使用字典UITableViewCell。除非該標識符專用於該單元,否則您不得在此類單元上調用dequeueReusableCellWithIdentifier;而對於大型數據集而言,高度的內存效率低下,這將保證單元不被重新使用。


2.不要猜tableview

- (UITableViewCell *)tableView:(UITableView *)tableView 
     cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    cellHistory = [self.notificationTableView // etc. 

正確的邏輯UITableViewDataSourcecellForRowAtIndexPath是使用傳遞給你的參數:

- (UITableViewCell *)tableView:(UITableView *)tableView 
     cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    cellHistory = [tableView // etc. 

3 。再用乾淨的再生細胞

假設你已經掌握了使用dequeueReusableCellWithIdentifier的回收副作用,並確保你不交叉授粉不同類型的細胞,你可能要cleanup您的重用單元(信貸Timur Bernikowich對他的評論)

func prepareForReuse() { 
    super.prepareForReuse() 
    // reset attributes of the cell that are not related to content 
} 

4.內省第一

總是比較喜歡,我做錯了什麼它曾經工作在以前的操作系統。雖然第二個命題通常是正確的,但總的來說,歷史可以讓你思考如何在天堂裏工作。

恰恰相反,我通常把這些情況作爲一個確定的信號,我正在做一些可怕的錯誤,我只是幸運地穿過了裂縫。


5.尊重命名約定

雖然我欣賞你塊通過在所述方法中

- (void)setLinksForSubstrings:(NSArray*)string withLinkHandler:(void(^)(FRHyperLabel *label, NSString *substring))handler {} 

我有點由Details對象或userName的性質揭去,更不用說在[self userNameTapped:[[[[中的4個括號。如果我被拋棄,其他工程師在第一次接觸到您的代碼時會有機會。

從上下文中,我不能推導出什麼是變量,常量,靜態,實例屬性等。很可能你的單元格在這個層次上被混淆了(你可能會重複使用你認爲是當地人或基於堆棧的值,但不是)。

我可以建議使用typedef作爲塊,採用大小寫一致性,避免嵌套[太深。花了不小的努力將代碼與樣板UITableView代碼進行比較,只是爲了修剪噪音。

+2

我不得不不同意在需要修改時專用持久單元。更明確的方法是修改模型中的數據,然後調用'reloadRowsAtIndexPaths:withRowAnimation:',或重新加載部分的類似方法。 – Losiowaty

+1

我完全同意。我認爲第1項是非常明確的,不掛在返回的'UITableViewCell'上。我已添加對您的評論的參考。 – SwiftArchitect

+1

不是由'UITableView'調用的'prepareForReuse'? –

相關問題