从Nib加载可重用的UITableViewCell

时间:2009-01-05 18:12:53

标签: ios iphone uitableview cocoa-touch interface-builder

我可以使用http://forums.macrumors.com/showthread.php?t=545061中找到的线程中描述的技术设计自定义UITableViewCells并加载它们。但是,使用该方法不再允许您使用reuseIdentifier初始化单元格,这意味着您必须在每次调用时创建每个单元格的全新实例。有没有人想出一个很好的方法来缓存特定的单元格类型以便重用,但仍然可以在Interface Builder中设计它们?

16 个答案:

答案 0 :(得分:119)

实际上,由于您在Interface Builder中构建单元格,只需在其中设置重用标识符:

IB_reuse_identifier

或者如果您正在运行Xcode 4,请检查“属性”检查器选项卡:

enter image description here

(编辑:你的XIB是由XCode生成的,它包含一个空的UIView,但是我们需要一个UITableViewCell;所以你必须手动删除UIView并插入一个Table View Cell。当然,IB不会显示任何UITableViewCell UIView的参数。)

答案 1 :(得分:74)

只需使用适当的方法签名实现方法:

- (NSString *) reuseIdentifier {
  return @"myIdentifier";
}

答案 2 :(得分:66)

现在,在iOS 5中有一个适当的UITableView方法:

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

答案 3 :(得分:47)

我不记得我最初在哪里找到了这段代码,但到目前为止它一直对我有用。

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

    static NSString *CellIdentifier = @"CustomTableCell";
    static NSString *CellNib = @"CustomTableCellView";

    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
        cell = (UITableViewCell *)[nib objectAtIndex:0];
    }

    // perform additional custom work...

    return cell;
}

示例界面生成器设置...

alt text

答案 4 :(得分:12)

看看我对这个问题给出的答案:

Is it possible to design NSCell subclasses in Interface Builder?

不仅可以在IB中设计UITableViewCell,这是可取的,因为否则所有手动布线和多个元素的放置都非常繁琐。只要您在可能的情况下小心使所有元素都不透明,性能就可以了。在IB中为UITableViewCell的属性设置了reuseID,然后在尝试出列时在代码中使用匹配的重用ID。

去年WWDC的一些主持人也听说你不应该在IB中制作桌面视图单元格,但它是一堆上下铺。

答案 5 :(得分:7)

从iOS大约4.0开始,iOS文档中有一些特定的说明可以让这项工作变得非常快:

http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html#//apple_ref/doc/uid/TP40007451-CH7

向下滚动到它谈论子类化UITableViewCell的地方。

答案 6 :(得分:6)

这是另一种选择:

NSString * cellId = @"reuseCell";  
//...
NSArray * nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:nil options:nil];

for (id obj in nibObjects)
{
    if ([obj isKindOfClass:[CustomTableCell class]])
    {
        cell = obj;
        [cell setValue:cellId forKey:@"reuseIdentifier"];
        break;
    }
}

答案 7 :(得分:2)

路易斯方法为我工作。这是我用来从笔尖创建UITableViewCell的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCellId"];

    if (cell == nil) 
    {
        UIViewController *c = [[UIViewController alloc] initWithNibName:@"CustomCell" bundle:nil];
        cell = (PostCell *)c.view;
        [c release];
    }

    return cell;
}

答案 8 :(得分:2)

我以类似的方式创建自定义视图单元格 - 除了我通过IBOutlet连接单元格。

[nib objectAt...]方法很容易改变数组中项目的位置。

UIViewController方法很好 - 只是试了一下,而且效果还不错。

但是...

在所有情况下都不会调用initWithStyle构造函数,因此不会进行默认初始化。

我已经阅读了有关使用initWithCoderawakeFromNib的各种地方,但没有确凿的证据证明其中任何一种都是正确的方法。

除了在cellForRowAtIndexPath方法中显式调用某些初始化方法之外,我还没有找到答案。

答案 9 :(得分:2)

前段时间我在blog.atebits.com找到了关于这个主题的精彩博文,并且从那时起开始使用Loren Brichter ABTableViewCell类来完成我的所有UITableViewCells。

你最终得到一个简单的容器UIView来放置你的所有小部件,并且滚动很快。

希望这很有用。

答案 10 :(得分:2)

此技术也有效,并且在视图控制器中不需要时髦的ivar来进行内存管理。 这里,自定义表视图单元格位于名为“CustomCell.xib”的xib中。

 static NSData *sLoadedCustomCell = nil;

 cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
 if (cell == nil) 
 {
   if (sLoadedCustomCell == nil) 
   {        
      // Load the custom table cell xib
      // and extract a reference to the cell object returned
      // and cache it in a static to avoid reloading the nib again.

      for (id loadedObject in [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil]) 
      {
        if ([loadedObject isKindOfClass:[UITableViewCell class]]) 
        {
          sLoadedCustomCell = [[NSKeyedArchiver archivedDataWithRootObject: loadedObject] retain];
          break;
        }
    }
    cell = (UITableViewCell *)[NSKeyedUnarchiver unarchiveObjectWithData: sLoadedCustomCell];
  }

答案 11 :(得分:2)

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

static NSString *simpleTableIdentifier = @"CustomCell";

CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    cell = [nib objectAtIndex:0];

    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}         

return cell;
}

答案 12 :(得分:1)

gustavogb解决方案对我不起作用,我尝试的是:

ChainesController *c = [[ChainesController alloc] initWithNibName:@"ChainesController" bundle:nil];
[[NSBundle mainBundle] loadNibNamed:@"ChaineArticleCell" owner:c options:nil];
cell = [c.blogTableViewCell retain];
[c release];

似乎有效。 blogTableViewCell是单元格的IBOutlet,ChainesController是文件的所有者。

答案 13 :(得分:1)

来自关于dequeueWithReuseIdentifier的UITableView文档:“标识要重用的单元格对象的字符串。默认情况下,可重用单元格的标识符是其类名,但您可以将其更改为任意值。”

重写-reuseIdentifer自己有风险。如果您有两个子类的子类,并在单个表视图中使用这两个子类,会发生什么?如果他们将重用标识符调用发送到超级,您将使错误类型的单元格出列..............我认为您需要覆盖reuseIdentifier方法,但让它返回一个取代的标识符串。或者,如果尚未指定,则让它将该类作为字符串返回。

答案 14 :(得分:0)

为了它的价值,我在一次iPhone Tech Talks上向iPhone工程师询问了这个问题。他的回答是,“是的,可以用IB来创造细胞。但不要。请不要。”

答案 15 :(得分:0)

我按照Ben Mosher链接Apple的说明(谢谢!)但发现Apple省略了重点。他们在IB中设计的对象只是一个UITableViewCell,它们从它加载的变量也是如此。但是,如果您实际将其设置为UITableViewCell的自定义子类,并编写子类的代码文件,则可以在代码中编写IBOutlet声明和IBAction方法,并将它们连接到IB中的自定义元素。然后,不需要使用视图标签来访问这些元素,您可以创建任何类型的疯狂单元格。这是可可触摸天堂。