分配accessoryView时UITableViewCell layoutSubviews上的死锁

时间:2013-08-30 23:54:52

标签: ios objective-c uitableview cocoa-touch uikit

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

我在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时的问题

When is layoutSubviews called?

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

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

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

或者我认为附件视图错了?

干杯!

编辑: 这是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;
}

1 个答案:

答案 0 :(得分:3)

单元格被重复使用,因此可以在另一个位置重新使用从屏幕滚动的单元格,您仍然可以在其中添加任何子视图。在特定indexPath处添加附件视图时,您需要在其中包含“else”子句,以告知其他单元格没有该视图:我不知道你在cellForRowAtIndexPath:中做了什么,但在我的测试方法中,我根本不必使用prepareForReuse方法。我不确定我理解为什么在切换方法触发时会出现死锁,但是如果你在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];
}