当UITableview向上或向下滚动时值发生了变化
我有一个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;
谨防
以下的答案必须解决的具体实施,而不是设计。使用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.
正确的逻辑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
代码进行比较,只是为了修剪噪音。
我不得不不同意在需要修改时专用持久单元。更明确的方法是修改模型中的数据,然后调用'reloadRowsAtIndexPaths:withRowAnimation:',或重新加载部分的类似方法。 – Losiowaty
我完全同意。我认为第1项是非常明确的,不挂在返回的'UITableViewCell'上。我已添加对您的评论的参考。 – SwiftArchitect
不是由'UITableView'调用的'prepareForReuse'? –
请提供更多代码,如何将数据设置到您的单元格中。 –
我已经更新了上面的代码。 – Nishan29
您的细胞正在被重复使用。基本的iOS设计知识。大量的例子在线 – soulshined