Uitableview 使用registernb:forCellReuseIdentifier:防止我与表单元格内的控件交互

Uitableview 使用registernb:forCellReuseIdentifier:防止我与表单元格内的控件交互,uitableview,ios5,nib,Uitableview,Ios5,Nib,我正在使用注册表nb:forCellReuseIdentifier:从nib b/c加载单元格,有人告诉我,有了它,我总能从[tableView DequeueReuseableCellWithIdentifier:]获取单元格,从而减少那些样板代码 我总是会得到一个单元格,但问题是我的IBAction(单元格中的一个按钮)由于引发异常“NSInvalidArgumentException”而开始失败,原因:xxx未识别的选择器发送到实例 如果我删除调用寄存器nb:forCellReuseIde

我正在使用注册表nb:forCellReuseIdentifier:从nib b/c加载单元格,有人告诉我,有了它,我总能从[tableView DequeueReuseableCellWithIdentifier:]获取单元格,从而减少那些样板代码

我总是会得到一个单元格,但问题是我的IBAction(单元格中的一个按钮)由于引发异常“NSInvalidArgumentException”而开始失败,原因:xxx未识别的选择器发送到实例

如果我删除调用寄存器nb:forCellReuseIdentifier:并像往常一样添加这些代码(如下所示),那么一切都可以正常工作。所以我猜问题是由这个电话引起的

那么我做错了什么

顺便说一句,我将cell nib文件的文件所有者设置为我的表视图控制器。在本例中,“编程iOS5”表示“不需要在nib中指定文件的所有者类”,但由于我需要设置IBAction,所以我仍然设置了它。我不认为这会造成问题,对吗

//The "old" codes without calling registerNib:forCellReuseIdentifier:
UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:@"MyCell"];
if (cell == nil) {
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"MyCell"
                                                 owner:self 
                                               options:nil];
    cell = [nib objectAtIndex:0];

您的iAction在加载单元格的控制器中,我想是吧?我想那是行不通的。如果您在dequeing时查看调用堆栈——就像我现在正在进行的调试一样——您将看到

- [YOURCELLCLASS awakeFromNib];
- [UINib instantiateWithOwner:options:]
- [UITableView dequeueReusableCellWithIdentifier:]
表视图如何知道应该将哪个控制器对象作为所有者传递给UINib,以匹配您声明的类?似乎没有办法做到这一点。事实上,当我复制上面的按钮并在awakeFromNib中检查其目标时,该目标肯定不是控制器;这样你就崩溃了。有趣的是,它似乎也不是表视图,这正是我所期望的;它是一个地址与乍一看不出的任何明显内容都不匹配的NSObject


不管怎么说,教训似乎是,在这个xib中,您不应该使用文件的所有者。将您的逻辑移动到单元格自定义类中,或者在取消查询后自行设置控件的目标。

我再次遇到了这个问题,并做了一些进一步的调查。这是我发现的

  • 在单元格nib中设置文件本身是毫无意义的(也是危险的)。我在xib中设置了file's own以将IBAction连接到MyCell类,但后来我意识到[[NSBundle mainBundle]loadNibNamed:owner:options:]中提供的所有者是运行时所尊重的所有者。验证这一点很容易,只需提供2个iAction(相同的方法名),一个在MyCell中,另一个在owner中,并观察调用了哪个
  • 有许多文章说,您可以通过调用
    cell=[[MyCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]来创建cell[[NSBundle mainBundle]loadNibNamed:owner:options:][/code>
  • 现在我有点相信这是一个bug,使用
    registernb:forCellReuseIdentifier:
    会将iAction设置为错误的目标,或者不能将其与iAction一起使用。正如@alexcurylo在使用它时所说的,无法正确设置文件的所有者(即使您在xib中设置了它)。这里问题的答案是运行时将所有者设置为nil。但奇怪的是IBOutlet总是设置正确
  • 因此,如果您只需要使用registernb:forCellReuseIdentifier更新IBOutlet的属性,例如更新UILabel的文本,那么b/c越简单,您总是会得到一个单元格,无需再次检查它。但如果需要操作,则必须在获取UIView后调用
    addTarget:action:
    (使用[[NSBundle mainBundle]loadNibNamed:owner:options:]或registernb:forCellReuseIdentifier:)
  • 要创建自定义的表格单元格,您可以将UITableViewCell子类化并将控件放入代码中,或者只使用cell xib文件,但无需同时执行这两项操作(许多文章也建议这样做)。因为您无法正确执行IBAction,并且您可以轻松地在没有IBAction的情况下获得子视图。仅使用xib可能更简单。使用xib文件时,请记住在单元格中设置子视图的标记,然后可以使用[cell viewWithTag:]获取UIView

  • 如果您想使用IB连接您的操作,我认为有两个主要选项:

  • 不要使用
    注册表nb:forCellReuseIdentifier:
    -使用旧式代码在
    单元格中手动加载nib
  • 将iActions发送给第一响应者,而不是文件所有者,公然违反