我有一个UITableview
,它有一些历史记录。我使用自定义单元格来处理标签,图像和按钮的显示。 UITableview
内有大约50行。但问题是当Tableview向上滚动时,第一个显示的行下面的行的值已经改变了。不确定Tableview究竟发生了什么。
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 :(得分:8)
以下答案涉及具体实施,而不是设计。使用NSFetchedResultsController
的样板代码可以防止此错误首先发生。 (Apple documentation)。不惜一切代价,避免在cellForRowAtIndexPath
返回后操纵单元格:你不拥有它。
<强> 1。重用的单元格未缓存
特别担心的是:
[self.arrayHistory objectAtIndex:indexPath.row]
不是因为那个特定的实例,而是因为它让我认为你在这个类的其他地方做出了假设:通过UITableViewCell
检索的dequeueReusableCellWithIdentifier
只不过是一个瞬态对象,纯粹使用但UITableView
用于显示。
完全相同的单元格实例将随着时间的推移而具有多个indexPath :这样的单元格可能会在更远的日期被缓存或操纵 。一旦作为cellForRowAtIndexPath
的最后一个语句返回,它可能不再次被访问,无论是通过某个异步方法的外部指针保留。始终将通过dequeueReusableCellWithIdentifier
获取的缓存表格视图的索引路径视为陈旧。
返回后,不修改单元格的内容。遵循下面Losiowaty概述的正确设计。
如果您必须修改已经返回到表视图的单元格的内容,那么如果您必须修改已经返回到表视图的单元格的内容,则必须使用例如UITableViewCell
的字典专用于持久单元格。您不能在这样的单元格上调用dequeueReusableCellWithIdentifier
,除非该标识符专用于该单元格;虽然大数据集的内存效率很高,但它可以保证不再使用单元格。
<强> 2。不要猜测tableview
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cellHistory = [self.notificationTableView // etc.
UITableViewDataSource
cellForRowAtIndexPath
中的正确逻辑是使用传递给您的参数:
- (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
代码,只是为了减少噪音。