【问题标题】:Setting style of UITableViewCell when using iOS 6 UITableView dequeueReusableCellWithIdentifier:forIndexPath:使用 iOS 6 UITableView dequeueReusableCellWithIdentifier:forIndexPath 时设置 UITableViewCell 的样式:
【发布时间】:2012-10-21 21:59:25
【问题描述】:

我正在尝试在 iOS 6 中为UITableView 使用新方法时如何设置UITableViewCellStyle

以前,在创建 UITableViewCell 时,我会更改 UITableViewCellStyle 枚举以在调用 initWithStyle: 时创建不同类型的默认单元格,但据我所知,情况已不再如此。

UITableView 的 Apple 文档指出:

返回值: 具有关联重用标识符的 UITableViewCell 对象。此方法总是返回一个有效的单元格。

讨论: 出于性能原因,表格视图的数据源在将单元格分配给其 tableView:cellForRowAtIndexPath: 方法中的行时,通常应该重用 UITableViewCell 对象。表视图维护数据源已标记为重用的 UITableViewCell 对象的队列或列表。当被要求为表格视图提供新单元格时,从您的数据源对象调用此方法。如果一个现有单元格可用,此方法会将现有单元格出列,或者根据您之前注册的类或 nib 文件创建一个新单元格。

重要提示:在调用此方法之前,您必须使用 registerNib:forCellReuseIdentifier: 或 registerClass:forCellReuseIdentifier: 方法注册类或 nib 文件。

如果您为指定的标识符注册了一个类并且必须创建一个新单元格,则此方法通过调用其 initWithStyle:reuseIdentifier: 方法来初始化该单元格。对于基于 nib 的单元格,此方法从提供的 nib 文件加载单元格对象。如果现有单元格可供重用,则此方法将调用该单元格的 prepareForReuse 方法。

这是我的新 cellForRowAtIndexPath 在实施新方法后的样子:

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

    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    return cell;
}

到目前为止,我的代码运行良好,但始终返回默认样式。如何更改此设置,以便创建具有其他样式的单元格,例如 UITableViewCellStyleDefaultUITableViewCellStyleValue1UITableViewCellStyleValue2UITableViewCellStyleSubtitle

我不想继承 UITableViewCell,我只想更改默认类型,就像在 iOS 6 之前我可以做的那样。Apple 会提供增强的方法但用最少的文档来支持它们的实现,这似乎很奇怪。

有没有人掌握了这个,或者遇到了类似的问题?我正在努力寻找任何合理的信息。

【问题讨论】:

    标签: uitableview ios6


    【解决方案1】:

    我知道你说过你不想创建子类,但它看起来是不可避免的。基于在 iOS 6.0 模拟器中测试时的汇编代码,UITableView 通过执行创建UITableViewCell(或其子类)的新实例

    [[<RegisteredClass> alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:<ReuseIdentifier>]
    

    换句话说,发送的样式 (UITableViewCellStyleDefault) 似乎是硬编码的。为了解决这个问题,您需要创建一个子类来覆盖默认初始化器 initWithStyle:reuseIdentifier: 并传递您希望使用的样式:

    - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        // ignore the style argument, use our own to override
        self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier];
        if (self) {
            // If you need any further customization
        }
        return self;
    }
    

    另外,最好在viewDidLoad 中发送registerClass:forCellReuseIdentifier:,而不是每次请求单元格时都发送:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [self.tableView registerClass:<RegisteredClass> forCellReuseIdentifier:<ReuseIdentifier>];
    }
    

    【讨论】:

    • 我开始假设情况确实如此。这不是一个主要问题,但必须继承 UITableViewCell 以获取其他默认样式是一件痛苦的事情,因为它只会创建不必要的文件。感谢您的评论并证实了我的怀疑。
    • 不要忘记,您可以使用旧的iOS5方法代替子类化,该方法仍然有效。这样您就可以自己初始化任何类型的单元格样式。查看其他答案。
    【解决方案2】:

    dequeueReusableCellWithIdentifier 未被弃用,因此您无需使用新的dequeueReusableCellWithIdentifier:forIndexPath:

    如果您使用自定义单元格类,请使用新方法和适当的注册方法(在 viewDidLoad 中),但如果您想使用 UITableViewCellStyle 枚举之一,请使用旧方法。

    【讨论】:

    • 赞成指出您不必必须使用花哨的新方法。仅当它们适合您的目的或替代方案已被弃用时。
    • 如果您特别热衷,可以覆盖 dequeueReusableCellWithIdentifier:forIndexPath: 以提供一些标识符以旧方式构建单元格(并返回它们)。其他标识符将调用 super 并返回它。为这种标识符的构造函数块设置一个NSDictionary 标识符可能是有意义的。
    【解决方案3】:

    您可以使用故事板界面构建器来避免无关的子类:

    1. 在 Storyboard 视图中,选择表格视图单元格原型单元格(在表格视图上)
    2. 在实用程序视图的属性检查器中,修改样式值
    3. (可选)修改其他值,例如 Selection 和 Accessory

    新的 iOS 6.0 dequeueReusableCellWithIdentifier:forIndexPath: 在分配新单元格并返回它们时确实使用了这些值。 (使用 Xcode 4.5.2 在 iOS 6.0 编译上测试)

    【讨论】:

      【解决方案4】:

      另一种保存文件的方法是创建一个 Nib 并改用 registerNib:forCellReuseIdentifier:

      制作 Nib 很简单:在 Interface Builder 中创建一个新的 .xib 文件。删除默认视图。添加一个表格视图单元格对象。使用属性检查器,更改单元格的样式。 (在这里您还可以通过调整其他属性来进一步自定义单元格。)

      然后在您的表视图控制器的 viewDidLoad 方法中调用类似:

      [self.tableView registerNib:[UINib nibWithNibName:@"StyleSubtitleTableCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"Cell"];
      

      【讨论】:

      • initWithStyle:reuseIdentifier 未被调用。
      【解决方案5】:

      Bolot 的答案是正确的。简单,无需创建任何 XIB 文件。

      我只是想为使用 Swift 而不是 Objective-C 的人更新他的答案:

      override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
          super.init(style: .value1, reuseIdentifier: reuseIdentifier)
      }
      
      required init?(coder aDecoder: NSCoder) {
          fatalError("init(coder:) has not been implemented")
      }
      

      【讨论】:

        【解决方案6】:

        我的解决方案是在我使用[self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath] 获得它之后调用initWithStyle: reuseIdentifier:。毕竟,init 只是另一个选择器,编译器对在已经初始化的对象上调用它没有任何限制。但是它会抱怨不使用调用 init 的结果,所以我这样做了:

        UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath];
        cell = [cell initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellId"];
        

        我想这在 Swift 中是行不通的……

        【讨论】:

        • imo 最优雅的解决方案。希望 initWithStyle 的胆量不会重新创建所有内容。
        • 好吧,我想如果你这样做,你可以完全放弃出队的东西......
        • 重用单元格是高性能 UITableView 的关键。您的解决方案建议不要重复使用单元格。
        • 当您第二次调用initWithStyle: reuseIdentifier 时,您实际上是在用新创建的对象覆盖单元格。是的,内存分配已经完成,新单元将覆盖相同的内存位置,但是当您再次初始化它时,实际上是在创建一个全新的对象。这否定了所有优化,即首先重用单元格的全部意义。
        • 不是一个很好的解决方案 - 如果您正在使用此解决方案,我认为至少完全放弃使单元格出队会更好
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-12
        • 2012-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多