为什么在 Apple 的 TheElements 示例中,cellForRowAtIndexPath 中返回的单元格不是 nil?

Why isn't a returned cell nil in cellForRowAtIndexPath in Apple's TheElements example?

我知道这个问题可能看起来有点奇怪,但我正在查看 Apple 示例 TheElements,并注意到他们的 cellForRowAtIndexPath 实现甚至不检查出队单元格是否为 nil。

如果您只是获取最新版本的 TheElements 示例,那不是我指的那个。您必须将 dequeueReusableCellWithIdentifier:forIndexPath: 替换为旧版本,即 dequeueReusableCellWithIdentifier.

这就是为什么我希望初始出列单元格为零:
来自 dequeueReusableCellWithIdentifier:...
的 Apple 文档 如果现有单元格可用,此方法会使现有单元格出队,或使用您之前注册的 class 或 nib 文件创建新单元格。如果没有可重复使用的单元格并且您没有注册 class 或 nib 文件,则此方法 returns nil.

但是,我运行通过调试器,发现第一次调用该方法时,返回的单元格有值。

而在我对 UIViewController 的简陋实现中,出队单元最初为零,直到它们被回收,正如 Apple 文档所解释的那样。

编辑

收到答案并检查后,没有 nil 单元格出列的原因很清楚:该示例使用了一个故事板,其中 table 视图控制器包含一个原型单元格。

这是我的实现,它检查单元格是否为零。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
                                      reuseIdentifier:CellIdentifier];
    }

    cell.textLabel.text = [_tableModel objectAtIndex:indexPath.row];

    return cell;
}

而且,这是示例中的实现,TheElements:

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

    AtomicElementTableViewCell *cell =
        (AtomicElementTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"AtomicElementTableViewCell"];

    // set the element for this cell as specified by the datasource. The atomicElementForIndexPath: is declared
    // as part of the ElementsDataSource Protocol and will return the appropriate element for the index row
    //
    cell.element = [self atomicElementForIndexPath:indexPath];

    return cell;
}

Whereas in my humble implementation of a UIViewController, the dequeued cells are initially nil, until they are recycled

所以,有点历史。

  • iOS 4 之前,您调用 dequeueReusableCellWithIdentifier: 获取您的细胞。最初的细胞都是零,直到你有足够大的一堆开始回收它们。因此,您需要检查 nil 并自己创建初始的单元格堆。

    这就是正在做的事情。

  • iOS5中,引入了故事板。使用故事板的一大优势是它可以作为细胞的来源。因此,dequeueReusableCellWithIdentifier:,如果与与情节提要中的标识符匹配的标识符一起使用,never return nil.

    这就是 The Elements 在您引用的代码中所做的。

  • iOS6来了dequeueReusableCellWithIdentifier:forIndexPath:。这使得故事板在 iOS 5 中所做的事情总是发生。通过注册单元格 class 或 nib 将其绑定到标识符, 通过将单元格标识符与故事板中的标识符匹配,您可以配置 table 所以也就是说,当您调用 dequeueReusableCellWithIdentifier:forIndexPath: 时,如果需要新单元格,table 会生成新单元格。因此,单元格永远不会为零。

    那是你应该做的。您使用 table 注册 UITableViewCell 作为您的单元格标识符;然后您使用该单元格标识符调用 dequeueReusableCellWithIdentifier:forIndexPath:,看哪,该单元格永远不会为零。

顺便说一下,我们现在是 iOS 8。所以你所做的不仅是过时的 - 它已经过时了四代人。

您可以学习以下两种方法。

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);

当使用storyboard时,tableview会注册一个nib或者类似nib的特殊标识符,你也可以在单元格的xib片段中自定义一个标识符。

如果您使用代码创建表格视图,则可以在 vc 的 viewDidLoad 方法中注册一个单元格 class。

那么您始终可以在表视图的回调中使用您注册的标识符使单元格出队。