向上或向下滚动UITableview时值已更改

时间:2015-11-01 10:17:32

标签: ios objective-c iphone uitableview ios9

我有一个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;

1 个答案:

答案 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代码,只是为了减少噪音。