UITableViewCell选择器setSelected:animated:被多次调用?

时间:2011-03-23 05:31:44

标签: iphone ios uitableview

我在自定义UITableViewCell类中发现了 setSelected:animated:的奇怪行为。我发现如果单击表格中的单元格,会多次调用此函数。我想知道这是正常行为还是我的代码中的错误。

为了帮助调试,我在我的自定义UITableViewCell类实现中修改了 setSelected:animated:函数:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

[super setSelected:selected animated:animated];

// Configure the view for the selected state.
if (selected)
    NSLog(@"Yes %X", &self);
else
    NSLog(@"No %X", &self);

}

如果我点击模拟器中的单元格,这就是我在控制台中获得的内容:

2011-03-22 22:05:26.963 marketPulse[3294:207] Yes BFFFDDD0
2011-03-22 22:05:26.964 marketPulse[3294:207] Yes BFFFDE30

你会认为我只会输入1个条目,因为我只点击了1个单元格。

如果我之后点击另一个单元格:

2011-03-22 22:07:11.014 marketPulse[3294:207] No BFFFD890
2011-03-22 22:07:11.016 marketPulse[3294:207] No BFFFDD00
2011-03-22 22:07:11.017 marketPulse[3294:207] Yes BFFFDDD0
2011-03-22 22:07:11.017 marketPulse[3294:207] Yes BFFFDE30

如果我连续两次点击相同的单元格,我会获得超过2

2011-03-22 22:08:41.067 marketPulse[3294:207] Yes BFFFDDD0
2011-03-22 22:08:41.068 marketPulse[3294:207] Yes BFFFDE30
2011-03-22 22:08:41.069 marketPulse[3294:207] Yes BFFFDE30

我点击同一个单元格的次数越多,我就会越多,如果之后点击其他单元格,我会得到很多

我在NSLog之前放了一个断点,看着调试器,似乎所有重复的调用都是来自同一个对象。

以下是我的 tableView:cellForRowAtIndexPath:函数的一部分,以便您可以看到我的单元格是如何处理的:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


static NSString *ContentCellIdentifier = @"newsTableCellContent";

UITableViewCell *cell;


//index of cell data in tableData
NSUInteger index = indexPath.row / 2;

...

//content of story
else if( [indexPath row] % 2 == 1 ) {

    cell = [tableView dequeueReusableCellWithIdentifier:ContentCellIdentifier];

    if (cell == nil) {
        NSArray *topLevelObjects = [[NSBundle mainBundle]
                                    loadNibNamed:@"newsTableCells"
                                    owner:nil options:nil];

        for (id currentObject in topLevelObjects) {
            if ( [currentObject isKindOfClass:[newsTableCellContent class]] ) {
                cell = currentObject;
                break;
            }
        }
    }

    ((newsTableCellContent *)cell).content.text = [[tableData objectAtIndex:index] description];

}   

return cell;
}

一切正常,所以很难判断重复调用 setSelected:animated:是否有意。如果这是正常操作,我可以使用其他方法,但我想知道是否发生这种情况。

由于

4 个答案:

答案 0 :(得分:13)

发生的事情只是UITableView跟踪表中选择的单元格。

由于在滚动大型表视图时会重复使用单元格,因此表格视图必须将所选单元格的列表分开。不仅如此,但每当它重用一个单元格时,它必须设置其选定的属性,因为它可能使用了之前化身的旧的无效selected状态。

当您点击一个单元格时,会发生以下几种情况:取消选择先前选择的单元格(使用setSelected:)。新单元格突出显示。它被去突出显示(至少如果你点击,而不是按住手指),并且因为选择了新单元格而调用了setSelected:方法。那是一个。

第二个调用是延迟执行调用,可能来自表视图尚不知道表的最终状态是什么的点。此调用转到_selectAllSelectedRows,顾名思义,它会在所有选定的行上调用'setSelected:animated:'。那是第二次通话。其原因很可能是由于表格视图处于“过渡”状态而解决潜在问题,但谁知道呢。

是否是一个错误是解释。重复调用的修复方法就是:

if (self.selected == selected) return;

在调用super之前(如果self.selected == selected,则不必调用super。)

答案 1 :(得分:3)

理想情况下,您不应该从代码中的任何位置调用setSelected。 UIKit将负责调用它。

如果要在 cellForRowAtIndexPath 方法中显示选中的单元格/行,只需调用

tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .None)

表示特定的indexPath。

再次永远不要明确调用setSelected,除非你真的想要。

答案 2 :(得分:2)

如果您正在使用iPad,这是正常行为。 (它只在iPhone上调用一次。)

为了停止获得多个" setSelected:YES"或多个" setSelected:NO",您所要做的就是:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

现在,点击任意一个单元格即可:

  • setSelected的1个条目:YES动画:否
  • tableView的一个条目:didSelectRowAtIndexPath:
  • setSelected的1个条目:NO animated:YES

因此,无论你做什么,呼叫现在都是稳定的。

答案 3 :(得分:1)

滚动表时绝对应该调用它。单元格被重用,这意味着,如果你在不可见区域滚动单元格将被重用和重新初始化,包括调用setSelected,它基本上是一个轻量级属性设置器。

如果你真的想看看发生了什么,请将一个NSLog添加到tableView:cellForRowAtIndexPath:这将记录indexPath和返回的单元格。

整个日志应该让您很好地了解内部和内部发生的情况。 我想它会是这样的(点击IndexPath 1:1)

以1:0(先前选择的单元格)给我单元格 取消选择1:0
再次给我1:0的单元格(取消选择后更新)
取消选择1:0(更新此单元格上的选定标记并触发动画)
给我1:1的单元格 选择1:1
再次给我1:1的单元格(选择后更新)
选择1:1(更新此单元格上的选定标记并触发动画)

再次单击选定的单元格只是略有不同 - 它不会触发取消选择,而是触发另一次更新。