在 IndexPath 使用 reloadRows 时出现奇怪的更新:在表中

Posted

技术标签:

【中文标题】在 IndexPath 使用 reloadRows 时出现奇怪的更新:在表中【英文标题】:Weird updates when using reloadRowsAtIndexPaths: in a table 【发布时间】:2010-10-31 17:04:22 【问题描述】:

我有一个表格,其中单元格中的附件视图按钮被自定义复选标记图标替换。如果启用了一对温度设置的时间间隔,则单元格行会显示一个复选标记,以及时间、加热和冷却值。如果时间被禁用,没有复选标记,timefield.text中显示的时间被修改为状态:“禁用”。当我使用reloadData 时,代码运行良好。但是,由于我一次只更新一行,这对于我正在使用的大表来说是多余的。我正在尝试使用reloadRowsAtIndexPaths:,但我得到的屏幕更新不仅会影响单击的单元格,还会影响单击的前一个单元格。我没有使用动画 (UITableViewRowAnimationNone),但将其更改为渐变动画 (UITableViewRowAnimationFade) 以查看发生了什么。果然,褪色发生在所需的表格行和不需要的表格行上。此外,当前单元格行的时间值出现在前一个单元格行时间字段中。一旦我继续单击一行,更新就没有问题,但是一旦我切换到另一行,我就会同时影响两行。这就像更新方法从某个地方捡起垃圾一样。

我还尝试将reloadRowsAtIndexPaths: 调用与对beginUpdatesendUpdates 的调用括起来,但没有任何变化。

显然我不了解这里的基本内容。我究竟做错了什么?这是有问题的方法:

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
   

  UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
  UIButton *button = (UIButton *)cell.accessoryView;

  BOOL checked;

  if (intervalDisabled[((indexPath.section * 4) + indexPath.row)] == NO) 
    checked = YES;
    intervalDisabled[((indexPath.section * 4) + indexPath.row)] = YES;
   else 
    checked = NO;
    intervalDisabled[((indexPath.section * 4) + indexPath.row)] = NO;
  

  UIImage *newImage = (checked) ? [UIImage imageNamed:@"unchecked.png"] : [UIImage imageNamed:@"checked.png"];
  [button setBackgroundImage:newImage forState:UIControlStateNormal];

  timeField.text = [NSString stringWithFormat:@"%@", [self.dateFormatter stringFromDate:[timeOfDays objectAtIndex:((indexPath.section * 4) + indexPath.row)]]];

  //[self.tableView reloadData]; <-- This works fine

  NSArray *rowArray = [NSArray arrayWithObject:indexPath];

  [self.tableView reloadRowsAtIndexPaths:rowArray withRowAnimation:UITableViewRowAnimationFade];

编辑:

好的。这是您要求的代码。我希望它有所帮助。我很乐意发布其他部分。抱歉,我还没有掌握在这个编辑器中格式化代码的窍门。

// Customized cell for setpoints

- (UITableViewCell *)setPointsCell:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath NSString *temperatureSymbol;

static NSString *kCustomCellID = @"setPointsCellID";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCustomCellID];
if (cell == nil)

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kCustomCellID] autorelease];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    cell.selectionStyle = UITableViewCellSelectionStyleBlue;


// Set up the cell. 
NSDictionary *dictionary = [listOfRows3 objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:@"Content"];
NSString *cellValue = [array objectAtIndex:indexPath.row];

//Set properties of label and add its text
cell.textLabel.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
cell.textLabel.text = cellValue;

// Add time field
timeField = [[UITextField alloc] init];
timeField.tag = (indexPath.section * 100) + (indexPath.row * 10) + TIME_FIELD;
CGRect frame = CGRectMake(80.0, 6.0, 90.0, 31.0);
timeField.frame = frame;
timeField.borderStyle = UITextBorderStyleRoundedRect;
timeField.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
//  timeField.backgroundColor = [UIColor clearColor];

timeField.textAlignment = UITextAlignmentRight;

// Check and handle situation where time interval is disabled
BOOL rowHasCheck;

if (intervalDisabled[((indexPath.section * 4) + indexPath.row)] == NO) 
    rowHasCheck = YES;
    timeField.text = [NSString stringWithFormat:@"%@", [self.dateFormatter stringFromDate:[timeOfDays objectAtIndex:((indexPath.section * 4) + indexPath.row)]]];
 else 
    rowHasCheck = NO;
    timeField.text = @"Disabled";


UIImage *image = (rowHasCheck) ? [UIImage imageNamed:@"checked.png"] : [UIImage imageNamed:@"unchecked.png"];

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect bFrame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = bFrame;  // match the button's size with the image size

[button setBackgroundImage:image forState:UIControlStateNormal];

// set the button's target to this table view controller so we can interpret touch events and map that to a NSIndexSet
[button addTarget:self action:@selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;


// Override default keyboard handler so we can use a picker instead
timeField.delegate = self;

[cell.contentView addSubview:timeField];

// Set up termperature (F or C) to display
if (temperatureScale == FAHRENHEIT) 
    temperatureSymbol = @"F";
 else 
    temperatureSymbol = @"C";


// Add heating setpoint field
UITextField *heatingSetPointField = [[UITextField alloc] init];
heatingSetPointField.tag = (indexPath.section * 100) + (indexPath.row * 10) + HEATING_FIELD;

frame = CGRectMake(180.0, 6.0, 52.0, 31.0);
heatingSetPointField.frame = frame;
heatingSetPointField.borderStyle = UITextBorderStyleBezel;
heatingSetPointField.backgroundColor = [UIColor colorWithRed:1.0 green:0.2 blue:0.2 alpha:1.0];
heatingSetPointField.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
heatingSetPointField.textAlignment = UITextAlignmentRight;

heatingSetPointField.text = [NSString stringWithFormat:@"%i %@", hSetpoints[((indexPath.section * 4) + indexPath.row)], temperatureSymbol];

// Override default delegate handler
heatingSetPointField.delegate = self;

[cell.contentView addSubview:heatingSetPointField];

// Add cooling setpoint field
UITextField *coolingSetPointField = [[UITextField alloc] init];
coolingSetPointField.tag = (indexPath.section * 100) + (indexPath.row * 10) + COOLING_FIELD;
frame = CGRectMake(240.0, 6.0, 52.0, 31.0);
coolingSetPointField.frame = frame;
coolingSetPointField.borderStyle = UITextBorderStyleBezel;
coolingSetPointField.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
coolingSetPointField.backgroundColor = [UIColor colorWithRed:0.4 green:0.4 blue:1.0 alpha:1.0];
coolingSetPointField.textAlignment = UITextAlignmentRight;
coolingSetPointField.text = [NSString stringWithFormat:@"%i %@", cSetpoints[((indexPath.section * 4) + indexPath.row)], temperatureSymbol];

// Override default delegate handler
coolingSetPointField.delegate = self;

[cell.contentView addSubview:coolingSetPointField];

[timeField release];
[heatingSetPointField release];
[coolingSetPointField release]; 

return cell;

【问题讨论】:

你能发布你的 cellForRowAtIndexPath 实现吗?我认为这可能与它有关。 好的,就是这样。这不是最漂亮的代码,而且我知道那些 addSubviews 会造成很大的内存泄漏。 【参考方案1】:

主要问题是您似乎在所有单元格中使用单个 timeField 引用。至少,应该在每个单元格中单独创建 timeField(就像 heatSetPointField 一样),然后使用它的标签从单元格中提取它。

还有许多其他问题(例如,当一个单元格被重复使用时,文本字段将被多次添加到每个单元格)。

我认为 reloadData 正在“工作”,因为您没有尝试向上/向下滚动表格视图并在单元格返回视图时看到错误数据。

您可能想阅读Table View Programming Guide(尤其是自定义单元格部分)并从更简单的表格视图单元格开始,然后一次添加一层复杂性,直到您达到目标。

【讨论】:

以上是关于在 IndexPath 使用 reloadRows 时出现奇怪的更新:在表中的主要内容,如果未能解决你的问题,请参考以下文章

什么 tableView.reloadRows(at: [indexPath], with: .none) 会像这样崩溃?

iphone reloadRows At IndexPath 奇怪的动画

tableView.reloadRows(at:[indexPath],带有:.none)会像这样崩溃吗?

Swift tableView.reloadRows 删除单元格

UITableView - reloadRows 方法创建奇怪的滚动错误

为啥调用 reloadRows 后,heightForRowAt 没有在数组中找到值?