iOS:CellForRowAtIndexPath单元格正在混淆

首先说我见过这些问题:

iOS:UITableView在滚动速度过快时会混合数据

(自定义)UITableViewCell在滚动后混音

在UITableView中滚动后混淆的项目

第一个和最后一个似乎与我的问题非常相关,但是我相当确定我有每个部分的逻辑来确定单元格中应该出现什么(数据),但它们仍然混淆了。

以下是相关代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //Note: the if (cell == nil) thing is no longer required in iOS 6 static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } if (closestRenter != nil) { NSLog(@"CLOSEST RENTER!"); [self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; } else { NSLog(@"NO CLOSEST RENTER"); [self setupCellsWithNoClosestRenterCell:cell atIndexPath:indexPath]; } if (indexPath.section == 0) { for (UIView *view in cell.contentView.subviews) { NSLog(@"WHAT THE HECK"); [view removeFromSuperview]; } } return cell; 

}

相关信息:

1)ClosestRenter不是……它存在。 所以else子句永远不应该被执行……就是这样。

2)在代码中:

 [self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; 

有一个简单的:

 if (indexPath.section == 0) { cell.textLabel.text = @"PLACE HOLDER"; } else { // Populate the cell with data. (creates a view (with controller etc) and loads it into the cell) } 

3)任何时候都有2个部分。

问题是第0部分(第一部分)应该只有那个占位符字符串。 第1部分应该包含我的自定义子视图(在单元格中,它确实如此)。

第0节最初只有占位符字符串,但是一旦我向下滚动(并且该部分不再可见)并向上滚动(快速),它有时会在第1部分中有一个看似随机的单元格……那到底是什么? 怎么样? 我不愿意责备细胞再利用,但在这一点之外我真的很傻,我不知道它是什么。

这里令人不安的部分是第0节中的单元格(那里只有一行)没有子视图。 但是当我快速向上和向下滚动时,它会得到一个(显然是第1部分),然后我得到了“WHAT THE HECK”日志消息……

值得一提的是,使用for循环(具有heck消息的那个)确实解决了问题(因为它删除了不需要的子视图),但必须有更好的方法。 现在感觉不对劲。

有任何想法吗?

(请随意将其标记为副本,但我相当确定此处还有其他内容)。

谢谢。

经过一点点挫折和仔细分析后,我发现了为什么细胞混淆了。

我对细胞重用(特别是标识符)的假设就是问题所在。

以前我这样做:

 static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } 

这是伟大的,但有一个关键问题。 所有细胞在技术上都是相同的…在它们全部分配(而不是零)后,系统无法确定哪个细胞可以重复使用,无论它是什么部分。

这意味着任何单元格都可以从队列中抓取,无论它有什么,并且卡在任何地方(尽管我的检查确保第1部分的内容进入第1部分,第0部分(假冒租借者)留在那里) 。

解决方案:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //Note: the if (cell == nil) thing is no longer required in iOS 6 static NSString *CellIdentifier1 = @"Cell"; static NSString *CellIdentifier2 = @"Cell2"; UITableViewCell *cell; if (indexPath.section == 0) { if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier1]; } else { cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1]; } } else { if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier1]; } else { cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2]; } } if (closestRenter != nil) { NSLog(@"CLOSEST RENTER!"); [self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; } else { NSLog(@"NO CLOSEST RENTER"); [self setupCellsWithNoClosestRenterCell:cell atIndexPath:indexPath]; } return cell; 

}

如您所见,第0部分将获得自己的单元标识符。 第1部分也是如此。结果是当一个单元格要出列时,它将检查indexPath当前所在的部分并获取正确的单元格。

呃,这么令人沮丧的问题,但现在一切都有道理:)

添加其他解决了我的问题。 我重置了对单元格所做的任何更改。

 if (! self.cell) { self.cell = [[LanguageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; self.cell.accessoryType = UITableViewCellAccessoryNone; } else { self.cell.checkImage.image = NO; } 

有几种方法可以解决这个单元重用问题(这就是问题所在),现在你正在这样做的方式还可以。 问题是,当您向下滚动并再次向上备份时,为第0部分返回的单元格可能是之前用于第1部分的单元格,因此它将包含您放入的任何子视图。

处理此问题的另一种方法是在故事板中创建两个不同的原型单元格,并返回一个带有第0部分的简单标签的单元格,并返回另一个,在IB中添加任何子视图,用于第1部分。这样,你将始终为每个部分获取正确的单元格类型,而不必删除任何子视图 – 您只需要使用正确的数据重新填充单元格。