2

我正在使用registerNib:forCellReuseIdentifier:从 nib b/c 加载单元格,有人告诉我,我总是可以从 [tableView dequeueReusableCellWithIdentifier:] 获取单元格,从而减少那些样板代码。

我总是得到一个单元格,但问题是我的 IBAction(我的单元格中的一个按钮)通过引发异常“NSInvalidArgumentException”开始失败,原因是:xxx unrecognized selector sent to instance。

如果我删除调用 registerNib:forCellReuseIdentifier: 并像往常一样添加这些代码(如下),一切正常。所以我猜这个问题是由这个电话引起的。

那么我做错了什么?

顺便说一句,我将单元格 nib 文件的文件所有者设置为我的表格视图控制器。“Programming IOS 5”在这种情况下说“无需在 nib 中指定 File's Owner 类”,但由于我需要设置 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];

...

4

3 回答 3

1

您的 IBAction 在加载单元格的控制器中,我接受吗?不要认为那会奏效。如果你在出队时查看调用堆栈——就像我现在正在做的一个调试点——你会看到

- [YOURCELLCLASS awakeFromNib];
- [UINib instantiateWithOwner:options:]
- [UITableView dequeueReusableCellWithIdentifier:]

表视图如何知道它应该将哪个控制器对象作为所有者传递给 UINib 以匹配您声明的类?似乎没有任何方法可以做到这一点。事实上,当我复制上面的按钮并在 -awakeFromNib 中检查其目标时,该目标绝对不是控制器;因此你的崩溃。有趣的是,它似乎也不是表格视图,这是我所期望的;它是一个 NSObject,其地址乍一看与任何明显的东西都不匹配。

耸耸肩无论如何,教训似乎是你不应该将文件的所有者用于此 xib 中的任何内容。将您的逻辑移动到单元格自定义类中,或在出队后自行设置控件的目标。

于 2012-08-31T18:58:31.730 回答
0

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

  1. 在单元格笔尖中设置自己的文件是没有意义的(而且很危险)。我在 xib 中设置了自己的文件以将我的 IBAction 连接到 MyCell 类,但后来我意识到 [[NSBundle mainBundle] loadNibNamed:owner:options:] 中提供的所有者是唯一受尊重的运行时。很容易验证,只需提供 2 个 IBActions(相同的方法名称),一个在 MyCell 中,另一个在 owner 中,然后观察调用了哪一个。
  2. 有很多文章说你可以通过调用来创建单元格cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];但我认为这是错误的。要使用 xib 文件中的单元格,您必须调用[[NSBundle mainBundle] loadNibNamed:owner:options:]
  3. 现在我有点相信这是一个错误,使用registerNib:forCellReuseIdentifier:会将您的 IBAction 设置为错误的目标,或者您不能将它与 IBAction 一起使用。就像@alexcurylo 在你使用它时所说的那样,无法正确设置文件的所有者(即使你已经在 xib 中设置了它)。这里问题的答案UITableView registerNib:forCellReuseIdentifier:说运行时只是将所有者设置为nil。但奇怪的是 IBOutlet 总是设置正确。
  4. 因此,如果您只需要更新 IBOutlet 的属性,例如更新 UILabel 的文本,使用 registerNib:forCellReuseIdentifier: 更简单 b/c 您总是会得到一个单元格,无需再次检查它为零。但是,如果您需要采取行动,则必须addTarget:action:在获得 UIView 后调用(使用 [[NSBundle mainBundle] loadNibNamed:owner:options:] 或 registerNib:forCellReuseIdentifier :)
  5. 要创建自定义表格单元格,您可以继承 UITableViewCell 并将控件放置在代码中,或者只使用单元格 xib 文件,但无需同时执行这两种操作(许多文章也建议这样做)。因为您不会正确地获得 IBAction,并且您可以在没有 IBOutlet 的情况下轻松获得子视图。只使用 xib 可能更简单。当您使用 xib 文件时,请记住在单元格中设置子视图的标签,然后您可以使用 [cell viewWithTag:] 获取 UIViews
于 2013-04-08T15:15:49.260 回答
0

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

  1. 不要使用-使用旧式代码registerNib:forCellReuseIdentifier:手动加载笔尖。cellForRowAtIndexPath:
  2. 将 IBActions 发送给 First Responder 而不是文件所有者,这公然违反​​了Guy English 的建议
于 2014-10-01T14:45:45.730 回答