使用iOS 6时UITableViewCell的设置样式UITableView dequeueReusableCellWithIdentifier:forIndexPath:


82

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

以前,当创建一个UITableViewCellI时,我将更改UITableViewCellStyle枚举以在调用时创建不同类型的默认单元格,initWithStyle:但从我可以收集的信息来看,情况已不再如此。

Apple文档UITableView指出:

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

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

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

如果您为指定的标识符注册了一个类,并且必须创建一个新的单元格,则此方法通过调用其initWithStyle:reuseIdentifier:方法来初始化该单元格。对于基于笔尖的单元格,此方法从提供的笔尖文件中加载单元格对象。如果现有单元可供重用,则此方法改为调用单元的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之前一样。苹果提供增强的方法但支持其实现的文档最少的情况似乎很奇怪。

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

Answers:


106

我知道您说过您不想创建一个子类,但这看起来是不可避免的。在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;
}

另外,最好发送registerClass:forCellReuseIdentifier:in viewDidLoad,而不是每次请求一个单元时都发送:

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

4
我开始认为情况确实如此。这不是主要问题,但是必须子类化UITableViewCell以获取其他默认样式却很麻烦,因为它只会创建不必要的文件。感谢您的评论并证实我的怀疑。
CaptainRedmuff 2012年

11
不要忘记,可以使用旧的iOS5方法代替子类,该方法仍然有效。这样,您可以初始化自己想要的任何类型的单元格样式。查看其他答案。
SpacyRicochet

60

dequeueReusableCellWithIdentifier不被弃用,因此您不需要使用new dequeueReusableCellWithIdentifier:forIndexPath:

如果使用自定义单元格类,请使用新方法以及相应的注册方法(在viewDidLoad中),但如果要使用UITableViewCellStyle枚举之一,请使用旧方法。


1
Upvoted的指出你不必须使用花哨的新方法。仅当它们适合您的目的或不推荐使用替代方法时。
SpacyRicochet

如果您特别热衷,可以覆盖dequeueReusableCellWithIdentifier:forIndexPath:以旧的方式提供一些标识符来构建单元格(并返回它们)。其他标识符将调用super并返回该标识符。NSDictionary对于此类标识符,在构造函数块中使用一个标识符可能是有意义的。
约翰

11

您可以通过使用故事板界面构建器来避免多余的子类:

  1. 在情节提要面板视图中,选择表格视图单元格原型单元格(在表格视图上)
  2. 在“实用工具”视图的“属性”检查器中,修改“样式”值
  3. (可选)修改其他值,例如“选择”和“附件”

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


7

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

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

然后在表视图控制器的viewDidLoad方法中调用类似以下内容的方法:

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

不调用initWithStyle:reuseIdentifier。
thierryb 2014年

0

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")
}

-5

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

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

我想这在Swift中行不通...


最优雅的解决方案imo。希望initWithStyle的勇气不会再次创建所有内容。
Scott Birksted

2
好吧,我想如果您这样做的话,您可以将所有出队的东西全部丢弃……
stk 2016年

1
重用单元格是高性能UITableView的关键。您的解决方案建议不要重复使用单元格。
Berik

2
当您initWithStyle: reuseIdentifier第二次调用时,实际上是在用新创建的对象覆盖单元格。是的,内存的分配已经完成,新单元将覆盖相同的内存位置,但是当您再次初始化它时,实际上是在创建一个全新的对象。这否定了所有优化,而这些优化首先是重用单元格的重点。
AnthonyMDev '16

1
不是一个很好的解决方案-如果您使用的是此解决方案,我认为至少完全放弃对单元出队更好
Sudara
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.