问题很简单:如何UITableViewCell从 Xib 文件加载自定义?这样做允许您使用 Interface Builder 来设计您的单元格。由于内存管理问题,答案显然并不简单。该线程提到了该问题并提出了解决方案,但它是 NDA 发布之前的版本并且缺少代码。这是一个很长的帖子,讨论了这个问题,但没有提供明确的答案。
UITableViewCell
这是我使用过的一些代码:
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并添加IBOutlets。然后创建一个新的“空 XIB”文件。在 IB 中打开 Xib 文件,添加一个UITableViewCell对象,将其标识符设置为“MyCellIdentifier”,并将其类设置为 MyCell 并添加您的组件。最后,连接IBOutlets到组件。请注意,我们没有在 IB 中设置文件的所有者。
IBOutlets
其他方法提倡设置文件的所有者,如果 Xib 没有通过额外的工厂类加载,则会警告内存泄漏。我在 Instruments/Leaks 下测试了上述内容,没有发现内存泄漏。
那么从 Xibs 加载单元的规范方法是什么?我们设置文件的所有者吗?我们需要工厂吗?如果是这样,工厂的代码是什么样的?如果有多种解决方案,让我们澄清每个解决方案的优缺点......
以下是原作者陈述的 IB 工程师推荐的两种方法。
有关更多详细信息,请参阅实际帖子。我更喜欢方法#2,因为它看起来更简单。
方法#1:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BDCustomCell"]; if (cell == nil) { // Create a temporary UIViewController to instantiate the custom cell. UIViewController *temporaryController = [[UIViewController alloc] initWithNibName:@"BDCustomCell" bundle:nil]; // Grab a pointer to the custom cell. cell = (BDCustomCell *)temporaryController.view; [[cell retain] autorelease]; // Release the temporary UIViewController. [temporaryController release]; } return cell; }
方法#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; }
更新(2014 年): 方法 #2 仍然有效,但不再有相关文档。它曾经在官方文档中,但现在被删除以支持故事板。
我在 Github 上发布了一个工作示例: https ://github.com/bentford/NibTableCellExample
为 Swift 4.2 编辑
override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. self.tblContacts.register(UINib(nibName: CellNames.ContactsCell, bundle: nil), forCellReuseIdentifier: MyIdentifier) } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: MyIdentifier, for: indexPath) as! ContactsCell return cell }