问题很简单:如何从Xib文件加载自定义UITableViewCell ?这样做允许您使用Interface Builder来设计单元格。由于内存管理问题,答案显然并不简单。这个帖子提到了这个问题,并提出了一个解决方案,但是在nda发布之前,缺乏代码。这里有一个很长的帖子,讨论了这个问题,但没有提供明确的答案。

下面是我使用的一些代码:

static NSString *CellIdentifier = @"MyCellIdentifier";

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

要使用这段代码,创建MyCell.m/.h,这是UITableViewCell的一个新子类,并为您想要的组件添加iboutlet。然后创建一个新的“Empty XIB”文件。在IB中打开Xib文件,添加一个UITableViewCell对象,将其标识符设置为“MyCellIdentifier”,并将其类设置为MyCell并添加组件。最后,将iboutlet连接到组件。注意,我们没有在IB中设置文件的所有者。

其他方法主张设置文件的所有者,如果Xib没有通过额外的工厂类加载,则警告内存泄漏。我在Instruments/Leaks下测试了上面的内容,没有发现内存泄漏。

那么从xib加载单元格的规范方法是什么呢?我们设置文件的所有者吗?我们需要工厂吗?如果是,工厂的代码是什么样子的?如果有多种解决方案,让我们来阐明每一种方案的优缺点。


当前回答

我使用了bentford的方法#2:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BDCustomCell"];
    if (cell == nil) {
        // Load the top-level objects from the custom cell XIB.
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"BDCustomCell" owner:self options:nil];
        // Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
        cell = [topLevelObjects objectAtIndex:0];
    }

    return cell;
}

它是有效的,但要注意在自定义UITableViewCell .xib文件中连接到File's Owner。

通过在loadNibNamed语句中传递owner:self,你将UITableViewController设置为UITableViewCell的文件所有者。

如果你拖拽到IB中的头文件来设置动作和出口,默认情况下它会将它们设置为file 's Owner。

在loadNibNamed:owner:options中,苹果的代码将尝试在你的UITableViewController上设置属性,因为那是所有者。但是你没有在那里定义这些属性,所以你得到一个关于键值编码兼容的错误:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason:     '[<MyUITableViewController 0x6a383b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key myLabel.'

如果一个事件被触发,你会得到一个NSInvalidArgumentException:

-[MyUITableViewController switchValueDidChange:]: unrecognized selector sent to instance 0x8e9acd0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyUITableViewController switchValueDidChange:]: unrecognized selector sent to instance 0x8e9acd0'
*** First throw call stack:
(0x1903052 0x15eed0a 0x1904ced 0x1869f00 0x1869ce2 0x1904ec9 0x5885c2 0x58855a 0x62db76 0x62e03f 0x77fa6c 0x24e86d 0x18d7966 0x18d7407 0x183a7c0 0x1839db4 0x1839ccb 0x1f8b879 0x1f8b93e 0x585a9b 0xb904d 0x2c75)
terminate called throwing an exceptionCurrent language:  auto; currently objective-c

一个简单的解决方法是将你的接口构建器连接指向UITableViewCell而不是File的Owner:

右键单击File's Owner调出连接列表 用Command-Shift-4进行屏幕捕捉(拖动以选择要捕捉的区域) x输出来自文件所有者的连接 右键单击对象层次结构中的UITableCell并重新添加连接。

其他回答

我决定发帖,因为我不喜欢这些答案——事情总是可以更简单,这是迄今为止我发现的最简洁的方法。

1. 在接口生成器中构建你的Xib,因为你喜欢它

将File's Owner设置为类NSObject 添加一个UITableViewCell,并将它的类设置为MyTableViewCellSubclass——如果你的IB崩溃(在Xcode > 4中发生),只要在Xcode 4中使用一个UIView来做接口,如果你仍然有它在周围 在这个单元格中布局子视图,并将IBOutlet连接以.h或.m(。M是我的首选)

2. 在你的UIViewController或UITableViewController子类中

@implementation ViewController

static NSString *cellIdentifier = @"MyCellIdentier";

- (void) viewDidLoad {

    ...
    [self.tableView registerNib:[UINib nibWithNibName:@"MyTableViewCellSubclass" bundle:nil] forCellReuseIdentifier:cellIdentifier];
}

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyTableViewCellSubclass *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    ...

    return cell;
}

3.在你的mytableviewcell子类中

- (id) initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        ...
    }

    return self;
}

我不知道是否有一个规范的方法,但以下是我的方法:

为ViewController创建一个xib 将File Owner类设置为UIViewController 删除视图并添加一个UITableViewCell 将UITableViewCell的类设置为自定义类 设置UITableViewCell的标识符 设置你的视图控制器视图的出口到你的UITableViewCell

并使用这段代码:

MyCustomViewCell *cell = (MyCustomViewCell *)[_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
  UIViewController* c = [[UIViewController alloc] initWithNibName:CellIdentifier bundle:nil];
  cell = (MyCustomViewCell *)c.view;
  [c release];
}

在你的例子中,使用

[nib objectAtIndex:0]

如果苹果改变xib中项目的顺序,可能会中断。

 NSString *CellIdentifier = [NSString stringWithFormat:@"cell %ld %ld",(long)indexPath.row,(long)indexPath.section];


    NewsFeedCell *cell = (NewsFeedCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    cell=nil;

    if (cell == nil)
    {
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"NewsFeedCell" owner:nil options:nil];

        for(id currentObject in topLevelObjects)
        {
            if([currentObject isKindOfClass:[NewsFeedCell class]])
            {
                cell = (NewsFeedCell *)currentObject;
                break;
            }
        }
}
return cell;

检查这个- http://eppz.eu/blog/custom-uitableview-cell/ -非常方便的方式使用一个小类,在控制器实现中结束一行:

-(UITableViewCell*)tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
    return [TCItemCell cellForTableView:tableView
                          atIndexPath:indexPath
                      withModelSource:self];
}

从UITableViewCell创建自己的自定义类AbcViewCell子类(确保你的类文件名和nib文件名是相同的) 创建这个扩展类方法。 扩展UITableViewCell { class func fromNib<T: UITableViewCell>() -> T { Bundle.main返回。loadNibNamed(字符串(描述:T.self),所有者:nil,选项:nil)?[0]一样!T } } 使用它。 let cell: AbcViewCell = UITableViewCell.fromNib()