问题很简单:如何从Xib文件加载自定义 UITableViewCell
?这样做允许您使用Interface Builder来设计单元格 . 由于内存管理问题,答案显然并不简单 . This thread提到了这个问题并建议了一个解决方案,但是在NDA发布之前并且没有代码 . 这是一个long thread,在没有提供明确答案的情况下讨论了这个问题 .
这是我用过的一些代码:
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
. 然后创建一个新的"Empty XIB"文件 . 在IB中打开Xib文件,添加 UITableViewCell
对象,将其标识符设置为"MyCellIdentifier",并将其类设置为MyCell并添加组件 . 最后,将 IBOutlets
连接到组件 . 请注意,我们没有在IB中设置文件所有者 .
如果未通过其他工厂类加载Xib,则其他方法主张设置文件所有者并警告内存泄漏 . 我在Instruments / Leaks下测试了上面的内容,没有发现内存泄漏 .
那么从Xibs加载单元格的规范方法是什么?我们设置文件所有者吗?我们需要工厂吗?如果是这样,工厂的代码是什么样的?如果有多种解决方案,让我们澄清每种解决方案的优缺点......
23 回答
这里有两种方法original author states was recommended by an IB engineer .
有关详细信息,请参阅实际帖子 . 我更喜欢方法#2,因为它似乎更简单 .
Method #1:
Method #2:
Update (2014): 方法#2仍然有效,但不再有文档了 . 它曾经在official docs但现在被删除,有利于故事板 .
我在Github上发布了一个工作示例:
https://github.com/bentford/NibTableCellExample
正确的解决方案是:
注册
在iOS 7之后,此过程已简化为( swift 3.0 ):
出队
然后,使用( swift 3.0 )出列队列:
不同之处在于这种新方法不仅使单元格出列,而且如果不存在则会产生(这意味着您不必执行
if (cell == nil)
shenanigans),并且单元格已准备就绪,就像上面的示例一样 .当然,单元格的关联类的类型是您在.xib文件中为
UITableViewCell
子类定义的类型,或者使用其他寄存器方法 .配置
理想情况下,您的单元格在注册时已经根据外观和内容定位(如标签和图像视图)进行了配置,而在
cellForRowAtIndexPath
方法中,您只需将其填入 .一起
当然,这在ObjC中都有相同的名称 .
拿起Shawn Craver的回答并清理了一下 .
BBCell.h:
BBCell.m:
我制作了所有UITableViewCell的BBCell子类,然后替换标准
有:
我用过bentford的 Method #2 :
It works, but watch out for connections to File's Owner in your custom UITableViewCell .xib file.
通过在
loadNibNamed
语句中传递owner:self
,可以将UITableViewController
设置为UITableViewCell
的文件所有者 .如果拖放到IB中的头文件以设置操作和出口,默认情况下会将其设置为文件所有者 .
在
loadNibNamed:owner:options
中,Apple的代码将尝试在UITableViewController
上设置属性,因为's the owner. But you don' t具有在那里定义的那些属性,因此您会收到关于符合键值编码的错误:如果事件被触发,您将获得NSInvalidArgumentException:
An easy workaround is to point your Interface Builder connections at the UITableViewCell instead of File's Owner:
右键单击文件所有者以提取连接列表
使用Command-Shift-4进行屏幕捕获(拖动以选择要捕获的区域)
x了文件所有者的连接
右键单击Object层次结构中的UITableCell并重新添加连接 .
我决定发帖,因为我不喜欢任何这些答案 - 事情总是更简单,这是迄今为止我发现的最简洁的方式 .
1. Build your Xib in Interface Builder as you like it
将文件所有者设置为类NSObject
添加UITableViewCell并将其类设置为MyTableViewCellSubclass - 如果您的IB崩溃(在撰写本文时发生在Xcode> 4中),只需使用UIView在Xcode 4中执行该接口,如果您仍然存在它
在此单元格内布置子视图,并将您的IBOutlet连接附加到.h或.m中的@interface(.m是我的偏好)
2. In your UIViewController or UITableViewController subclass
3. In your MyTableViewCellSubclass
如果您正在使用Interface Builder制作单元格,检查您是否在检查器中设置了标识符 . 然后在调用dequeueReusableCellWithIdentifier时检查它是否相同 .
我不小心忘了在一个表格繁重的项目中设置一些标识符,性能变化就像是白天和黑夜 .
从XIB加载UITableViewCells可以节省大量代码,但通常会导致可怕的滚动速度(实际上,它不是XIB,而是过度使用导致此问题的UIViews) .
我建议你看看这个:Link reference
这是我用来从XIB创建自定义单元格的类方法:
然后,在XIB中,我设置了类名,并重用了标识符 . 之后,我可以在视图控制器中调用该方法而不是
它比调用
[nib objectAtIndex:0]
更可靠,至少在我看来,比Stephan Burlot更可靠's example because you'保证只能从XIB中获取正确类型的视图 .正确的解决方案就是这样
重新加载NIB是昂贵的 . 最好加载一次,然后在需要单元格时实例化对象 . 请注意,您可以使用此方法将UIImageViews等添加到nib,甚至是多个单元格(Apple的“registerNIB”iOS5只允许一个顶级对象 - Bug 10580062“iOS5 tableView registerNib:过度限制”
所以我的代码在下面 - 你在NIB中读过一次(在初始化时像我一样或在viewDidload中 - 无论如何 . 从那时起,你将nib实例化为对象然后选择你需要的那个 . 这比加载nib更有效一遍又一遍 .
检查一下 - http://eppz.eu/blog/custom-uitableview-cell/ - 使用一个在控制器实现中结束一行的小类非常方便:
正确的方法是创建UITableViewCell子类实现,标头和XIB . 在XIB中删除任何视图,只需添加一个表格单元格 . 将类设置为UITableViewCell子类的名称 . 对于文件所有者,使其成为UITableViewController子类的类名 . 使用tableViewCell插座将文件所有者连接到单元 .
在头文件中:
在实现文件中:
我为此做的是在你的控制器类中声明一个
IBOutlet UITableViewCell *cell
. 然后调用NSBundle loadNibNamed
类方法,该方法将UITableViewCell
提供给上面声明的单元格 .对于xib,我将创建一个空的xib并在IB中添加
UITableViewCell
对象,可以根据需要进行设置 . 然后,此视图连接到控制器类中的单元格IBOutlet
.NSBundle additions loadNibNamed (ADC login)
cocoawithlove.com article I sourced the concept from (get the phone numbers sample app)
首先导入自定义单元格文件
#import "CustomCell.h"
,然后更改委托方法,如下所述:这是我的方法:Loading Custom UITableViewCells from XIB Files… Yet Another Method
我们的想法是创建
UITableViewCell
的SampleCell子类,其中包含IBOutlet UIView *content
属性以及您需要从代码配置的每个自定义子视图的属性 . 然后创建SampleCell.xib文件 . 在此nib文件中,将文件所有者更改为SampleCell . 添加内容UIView
大小以满足您的需求 . 添加和配置所需的所有子视图(标签,图像视图,按钮等) . 最后,将内容视图和子视图链接到文件所有者 .从
UITableViewCell
创建自己的自定义类AbcViewCell
子类(确保您的类文件名和nib文件名相同)创建此扩展类方法 .
let cell: AbcViewCell = UITableViewCell.fromNib()
我不知道是否有规范的方法,但这是我的方法:
为ViewController创建一个xib
将File Owner类设置为UIViewController
删除视图并添加UITableViewCell
将UITableViewCell的类设置为自定义类
设置UITableViewCell的标识符
将视图控制器视图的插座设置为UITableViewCell
并使用此代码:
在您的示例中,使用
如果Apple更改了xib中项目的顺序,可能会中断 .
此扩展需要Xcode7 beta6
创建一个仅包含1个自定义UITableViewCell的Xib文件 .
加载它 .
以下是在
UITableView
中注册单元格的通用方法:说明:
Reusable
协议从其类名生成单元ID . 确保遵循惯例:cell ID == class name == nib name
.UITableViewCell
符合Reusable
协议 .UITableView
扩展通过nib或类抽象注册单元格的差异 .用法示例:
在 Swift 4.2 和Xcode 10中
我有三个XIB单元文件
在ViewDidLoad中注册你的XIB文件......
这是第一种方法
第二种方法直接在 cellForRowAt indexPath: 中注册XIB文件
这是我的tableview委托函数