3

您好,我在我的应用程序上发现了一个问题,可能并不重要但很奇怪。

我的 viewController 中有一个开关,我们称它为 theSwitch,当我填充单元格时,在 indexPath (0,0) 上,我将该开关作为附件视图。

单元格的标题会根据开关的状态而变化

//Code simplified for simplicity 
if(indexPath.section == 0 && indexPath.row == 0) {
     cell.textLabel.text = self.filtersActivatedSwitch.on ? NSLocalizedString(@"Filters activated", nil) : NSLocalizedString(@"Filters deactivated", nil);
     cell.accessoryView = self.filtersActivatedSwitch;
}

当按下开关时,调用此方法

-(void)switchActivated {
     [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:VisibilityFilterTableViewSectionMasterFilter]];
}

这将造成死锁,因为在方法 cellForRowAtIndexPath 上,当我尝试使单元格出队时,它将创建一个新的(经过测试,我认为它使用了我想重新加载的相同单元格更有意义)并且在单元格的配置,开关将添加为附件视图...

这就是它变得棘手的地方......

BadPirate 的回答解释了何时在 tableviewcell 上调用 layoutSubview

什么时候调用 layoutSubviews?

-addSubview 导致 layoutSubviews 在被添加的视图、它被添加到的视图(目标视图)以及目标的所有子视图上调用

我认为 removeFromSupperview (假设)也应该发生同样的情况,所以新单元格调用了 layoutSubview .. 它检查附件视图,看到它不是 nil 所以它添加它作为子视图,另一方面在旧单元格中(即由于任何原因没有出队,所以我无法清除附件视图)layoutSubviews 被调用,因为 removeFromSuperview (再次假设)它检查附件视图不为零,它将开关添加为子视图......并永远重复。

我的问题是......为什么表格视图不使用已经出列的单元格?两个 tableviewcells 具有相同的附件视图这一事实显然会使我的应用程序崩溃。

还是我错误地使用了附件视图?

干杯!

编辑:这是prepareForReuse上的代码

- (void)prepareForReuse {
  [super prepareForReuse];

  for (UIView *view in self.contentView.subviews) {
      [view removeFromSuperview];
  }

  for (UIView *view in self.imageView.subviews) {
      [view removeFromSuperview];
  }

  self.textLabel.text = nil;
  self.detailTextLabel.text = nil;
  self.imageView.image = nil;
  self.imageView.tag = 0;
  self.accessoryView = nil;
}
4

1 回答 1

3

单元格被重用,因此滚动到屏幕外的单元格可以在另一个位置重用,您添加的任何子视图仍然存在。在特定的 indexPath 添加附件视图时,您需要在其中有一个“else”子句来告诉其他单元格没有该视图:。我不知道你在 cellForRowAtIndexPath: 中还做了什么,但是在我的测试方法中,我根本不需要使用 prepareForReuse 方法。我不确定我理解为什么在 switch 方法触发时会出现死锁,但是如果你在 reloadRowsAtIndexPaths:withRowAnimation: 方法中将动画设置为 UITableViewRowAnimationNone ,那么一切正常。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    if(indexPath.section == 0 && indexPath.row == 0) {
        cell.textLabel.text = self.filtersActivatedSwitch.on ? NSLocalizedString(@"Filters activated", nil) : NSLocalizedString(@"Filters deactivated", nil);
        cell.accessoryView = self.filtersActivatedSwitch;
    }else{
        cell.textLabel.text = self.theData[indexPath.row];
        cell.accessoryView = nil;
    }

    return cell;
}

-(void)switchActivated {

    [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}
于 2013-08-31T01:46:11.917 回答