如何从Xib文件加载自定义UITableViewCells?


293

问题很简单:如何UITableViewCell从Xib文件加载自定义?这样可以使您使用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,这是MyCell的新子类,UITableViewCellIBOutlets为所需的组件添加。然后创建一个新的“ Empty XIB”文件。在IB中打开Xib文件,添加一个UITableViewCell对象,将其标识符设置为“ MyCellIdentifier”,并将其类设置为MyCell并添加您的组件。最后,将连接IBOutlets到组件。请注意,我们没有在IB中设置文件的所有者。

其他方法提倡设置文件的所有者,如果没有通过其他工厂类加载Xib,则警告内存泄漏。我在“仪器/泄漏”下测试了以上内容,但没有发现内存泄漏。

那么从Xibs加载单元的规范方法是什么?我们是否设置文件的所有者?我们需要工厂吗?如果是这样,工厂的代码是什么样的?如果有多种解决方案,让我们阐明它们各自的优缺点...


2
有人可以编辑主题以实际提出问题吗,即“如何从Xib文件加载自定义UITableViewCells?” (忽略这是否在stackoverflow上是不可能的。)
Steven Fisher

1
对于iOS 5及更高版本,这是解决方案:stackoverflow.com/questions/15591364/…,与giuseppe的解决方案相同。
Matt Becker 2013年

快速笔记,简单(2013环境)答案在这里stackoverflow.com/questions/15378788/... jamihash
Fattie

Answers:


288

这是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
}

1
对于方法1,您是否应该执行类似“ cell =(BDCustomCell *)[[temporaryController.view keep] autorelease];”的操作?所以释放临时控制器时不会释放单元格吗?
Tod Cunningham

嗯 讨论#2的文档仍然告诉您将XIB文件中单元的所有者设置为已知的控制器类。在加载过程中设置所有者时可能没有关系。
奥斯卡

@OscarGoldman XIB文件中单元的所有者是一个类(即所有者的类型)。loadNibNamed:owner:options:中单元的所有者是XIB中指定类型的对象。
bentford 2011年

2
@CoolDocMan选项2仍然有效。笔尖最有可能出现问题。这是一个例子: github.com/bentford/NibTableCellExample
bentford

2
为什么这个超级老代码排名如此之高。Stackoverflow做一些事情:/
Nico S.19年

304

正确的解决方案是这样的:

- (void)viewDidLoad
{
    [super viewDidLoad];
    UINib *nib = [UINib nibWithNibName:@"ItemCell" bundle:nil];
    [[self tableView] registerNib:nib forCellReuseIdentifier:@"ItemCell"];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Create an instance of ItemCell
    PointsItemCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ItemCell"];

    return cell;
}

这会破坏iOS5应用程序吗?我真的从未见过UINib
亚当·威特

@AdamWaite注册NIB文件适用于iOS 5及更高版本,因此不会破坏iOS 5应用程序。而UINib甚至存在因为iOS的4
Mecki

举一个很好的例子,在这里查看顶部答案中引用的git repo:stackoverflow.com/questions/18746929/…–
netigger

39

寄存器

在iOS 7之后,此过程已简化为(swift 3.0):

// For registering nib files
tableView.register(UINib(nibName: "MyCell", bundle: Bundle.main), forCellReuseIdentifier: "cell")

// For registering classes
tableView.register(MyCellClass.self, forCellReuseIdentifier: "cell")

注意)这也可以通过在.xibor .stroyboard文件中创建单元格作为原型单元格来实现。如果需要将一个类附加到它们,则可以选择单元原型并添加相应的类(UITableViewCell当然必须是的后代)。

出队

然后,使用(swift 3.0)出队:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

    cell.textLabel?.text = "Hello"

    return cell
}

区别在于,此新方法不仅使单元出队,而且还会创建不存在的单元(这意味着您不必进行if (cell == nil)欺骗),并且单元可以像上面的示例中一样使用。

警告tableView.dequeueReusableCell(withIdentifier:for:)具有新行为,如果调用另一个行为(不带indexPath:),则会得到旧行为,在该行为中您需要自己检查nil并实例化它,请注意UITableViewCell?返回值。

if let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? MyCellClass
{
    // Cell be casted properly
    cell.myCustomProperty = true
}
else
{
    // Wrong type? Wrong identifier?
}

当然,单元的关联类的类型是您在.xib文件中为UITableViewCell子类定义的类型,或者使用其他注册方法。

组态

理想情况下,在您注册单元格时,就已经在外观和内容定位(如标签和图像视图)方面进行了配置,而cellForRowAtIndexPath您只需填写这些方法即可。

全部一起

class MyCell : UITableViewCell
{
    // Can be either created manually, or loaded from a nib with prototypes
    @IBOutlet weak var labelSomething : UILabel? = nil
}

class MasterViewController: UITableViewController 
{
    var data = ["Hello", "World", "Kinda", "Cliche", "Though"]

    // Register
    override func viewDidLoad()
    {
        super.viewDidLoad()

        tableView.register(MyCell.self, forCellReuseIdentifier: "mycell")
        // or the nib alternative
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return data.count
    }

    // Dequeue
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: "mycell", for: indexPath) as! MyCell

        cell.labelSomething?.text = data[indexPath.row]

        return cell
    }
}

当然,这些名称在ObjC中都可用。


这是objC版本:[self.tableView registerNib:[UINib nibWithNibName:@"BlaBlaTableViewCell" bundle:nil] forCellReuseIdentifier:kCellIdentifier];
Zeb

33

拿了肖恩·克雷弗(Shawn Craver)的答案,并做了一点整理。

BBCell.h:

#import <UIKit/UIKit.h>

@interface BBCell : UITableViewCell {
}

+ (BBCell *)cellFromNibNamed:(NSString *)nibName;

@end

BBCell.m:

#import "BBCell.h"

@implementation BBCell

+ (BBCell *)cellFromNibNamed:(NSString *)nibName {
    NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:NULL];
    NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
    BBCell *customCell = nil;
    NSObject* nibItem = nil;
    while ((nibItem = [nibEnumerator nextObject]) != nil) {
        if ([nibItem isKindOfClass:[BBCell class]]) {
            customCell = (BBCell *)nibItem;
            break; // we have a winner
        }
    }
    return customCell;
}

@end

我将所有UITableViewCell的子类都设为BBCell,然后替换标准

cell = [[[BBDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"BBDetailCell"] autorelease];

与:

cell = (BBDetailCell *)[BBDetailCell cellFromNibNamed:@"BBDetailCell"];

16

我使用了本特福德的方法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文件中与文件所有者的连接。

通过传递owner:self您的loadNibNamed声明,您将设置UITableViewController为的文件所有者UITableViewCell

如果您拖放到IB中的头文件以设置动作和出口,则默认情况下会将其设置为文件的所有者。

在中loadNibNamed:owner:options,Apple的代码将尝试在您的上设置属性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

一个简单的解决方法是将Interface Builder连接指向UITableViewCell而不是File Owner:

  1. 右键单击“文件的所有者”以拉起连接列表
  2. 使用Command-Shift-4进行屏幕截图(拖动以选择要捕获的区域)
  3. 从文件所有者中删除连接
  4. 在“对象”层次结构中的UITableCell上单击鼠标右键,然后重新添加连接。

我遇到了您提到的问题,但是如何将连接指向UITableViewCell而不是File的所有者?我不理解您的步骤,例如,为什么需要截屏?当我单击插座旁边的添加按钮时,什么也没发生
Xu Huanze 2013年

@xuhuanze我建议拍摄一张屏幕截图,以便您记录File的所有者已经连接到的东西。然后,您可以重新创建那些相同的连接。您需要拖放以添加连接-不仅仅是单击即可。
funroll

非常感谢,我遇到了“此类与键的键值编码不兼容”的问题,并在您的帮助下解决了该问题。我想告诉其他人,您还应该将UITableViewCell的类更改为用作自定义单元格类的类。
丹尼斯·库特鲁巴耶夫

14

我决定发布该帖子,因为我不喜欢这些答案中的任何一个-事情总是可以变得更简单,这是迄今为止我找到的最简洁的方法。

1.根据需要在Interface Builder中构建Xib

  • 将文件的所有者设置为NSObject类
  • 添加一个UITableViewCell并将其类设置为MyTableViewCellSubclass-如果您的IB崩溃(在撰写本文时,Xcode> 4发生了这种情况),如果您仍然将其放置在Xcode 4中,则只需使用UIView即可
  • 在此单元格内布置子视图,并将IBOutlet连接附加到.h或.m中的@interface(我偏爱.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.在您的MyTableViewCellSubclass中

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

    return self;
}

9

如果使用Interface Builder生成单元,请检查是否已在检查器中设置了标识符。然后在调用dequeueReusableCellWithIdentifier时检查是否相同。

我不小心忘记了在一个表多的项目中设置一些标识符,而性能的变化就像白天和黑夜。


8

从XIB加载UITableViewCells可以节省大量代码,但通常会导致可怕的滚动速度(实际上,不是XIB而是过度使用UIViews导致的)。

我建议您看一下:链接参考


6

这是我用来从XIB中创建自定义单元格的类方法:

+ (CustomCell*) createNewCustomCellFromNib {

    NSArray* nibContents = [[NSBundle mainBundle]
                            loadNibNamed:@"CustomCell" owner:self options:NULL];

    NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
    CustomCell *customCell= nil;
    NSObject* nibItem = nil;

    while ( (nibItem = [nibEnumerator nextObject]) != nil) {

        if ( [nibItem isKindOfClass: [CustomCell class]]) {
            customCell = (CustomCell*) nibItem;

            if ([customCell.reuseIdentifier isEqualToString: @"CustomCell"]) {
                break; // we have a winner
            }
            else
                fuelEntryCell = nil;
        }
    }
    return customCell;
}

然后,在XIB中,设置类名和重用标识符。之后,我可以在视图控制器中调用该方法,而不是

[[UITableViewCell] alloc] initWithFrame:]

它足够快,并且已在我的两个运输应用程序中使用。它比调用更可靠[nib objectAtIndex:0],并且至少在我看来,比斯蒂芬·伯洛特(Stephan Burlot)的示例更可靠,因为可以确保仅从正确类型的XIB中获取视图。


5

正确的解决办法是这样

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView registerNib:[UINib nibWithNibName:@"CustomCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"CustomCell"];
}

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

4

重新加载NIB很昂贵。最好一次加载一次,然后在需要单元格时实例化对象。请注意,您可以使用此方法将UIImageViews等添加到笔尖(甚至多个单元格)(Apple的“ registerNIB” iOS5仅允许一个顶级对象-错误10580062“ iOS5 tableView registerNib:过于严格”

所以我的代码在下面-您只需读取一次NIB(像我一样初始化或在viewDidload中-随便什么。从那时起,您将笔尖实例化为对象,然后选择所需的对象。这比加载笔尖更有效一遍又一遍。

static UINib *cellNib;

+ (void)initialize
{
    if(self == [ImageManager class]) {
        cellNib = [UINib nibWithNibName:@"ImageManagerCell" bundle:nil];
        assert(cellNib);
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"TheCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if(cell == nil) {
        NSArray *topLevelItems = [cellNib instantiateWithOwner:nil options:nil];
        NSUInteger idx = [topLevelItems indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)
                            {
                                UITableViewCell *cell = (UITableViewCell *)obj;
                                return [cell isKindOfClass:[UITableViewCell class]] && [cell.reuseIdentifier isEqualToString:cellID];
                            } ];
        assert(idx != NSNotFound);
        cell = [topLevelItems objectAtIndex:idx];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"Howdie %d", indexPath.row];

    return cell;
}

4

检查一下-http ://eppz.eu/blog/custom-uitableview-cell/-使用在控制器实现中只占一行的微型类的一种真正便捷的方式:

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

在此处输入图片说明


3

正确的方法是创建UITableViewCell子类实现,标头和XIB。在XIB中,删除所有视图,仅添加一个表格单元格。将类设置为UITableViewCell子类的名称。对于文件所有者,将其设为UITableViewController子类类名称。使用tableViewCell插座将文件所有者连接到单元。

在头文件中:

UITableViewCell *_tableViewCell;
@property (assign) IBOutlet UITableViewCell *tableViewCell;

在实现文件中:

@synthesize tableViewCell = _tableViewCell;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *kCellIdentifier = @"reusableCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:kCellIdentifier owner:self options:nil];
        cell = _tableViewCell;
        self.tableViewCell = nil;
    }

    return cell;
}

3

我要做的是IBOutlet UITableViewCell *cell在您的控制器类中声明一个。然后调用NSBundle loadNibNamedclass方法,该方法将把馈UITableViewCell给上面声明的单元格。

对于xib,我将创建一个空的xib,并将该UITableViewCell对象添加到IB中,可以根据需要对其进行设置。然后,此视图连接到IBOutlet控制器类中的单元。

- (UITableViewCell *)tableView:(UITableView *)table
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%@ loading RTEditableCell.xib", [self description] );

    static NSString *MyIdentifier = @"editableCellIdentifier";
    cell = [table dequeueReusableCellWithIdentifier:MyIdentifier];

    if(cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"RTEditableCell"
                                      owner:self
                                    options:nil];
    }

    return cell;
}

NSBundle添加loadNibNamed(ADC登录)

我从cocoawithlove.com文章中获得了这一概念(从获取电话号码示例应用程序)


3
  1. AbcViewCell从中创建您自己的自定义类子类UITableViewCell(确保您的类文件名和nib文件名相同)

  2. 创建此扩展类方法。

    extension UITableViewCell {
        class func fromNib<T : UITableViewCell>() -> T {
            return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)?[0] as! T
        }
    }
  3. 用它。

    let cell: AbcViewCell = UITableViewCell.fromNib()


2

首先导入您的自定义单元文件#import "CustomCell.h",然后按如下所述更改委托方法:

- (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;
}

2

Swift 4.2和Xcode 10中

我有三个XIB单元文件

在ViewDidLoad中像这样注册您的XIB文件...

这是第一种方法

tableView.register(UINib.init(nibName: "XIBCell", bundle: nil), forCellReuseIdentifier: "cell1")
tableView.register(UINib.init(nibName: "XIBCell2", bundle: nil), forCellReuseIdentifier: "cell2")
//tableView.register(UINib.init(nibName: "XIBCell3", bundle: nil), forCellReuseIdentifier: "cell3")

第二种方法直接在cellForRowAt indexPath中注册XIB文件

这是我的tableview委托函数

//MARK: - Tableview delegates
override func numberOfSections(in tableView: UITableView) -> Int {

    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return 6
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //This is first approach
    if indexPath.row == 0 {//Load first XIB cell
        let placeCell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! XIBCell
        return placeCell
    //Second approach
    } else if indexPath.row == 5 {//Load XIB cell3
        var cell = tableView.dequeueReusableCell(withIdentifier:"cell3") as? XIBCell3
        if cell == nil{
            let arrNib:Array = Bundle.main.loadNibNamed("XIBCell3",owner: self, options: nil)!
            cell = arrNib.first as? XIBCell3
        }

        //ADD action to XIB cell button
        cell?.btn.tag = indexPath.row//Add tag to button
        cell?.btn.addTarget(self, action: #selector(self.bookbtn1(_:)), for: .touchUpInside);//selector

        return cell!
    //This is first approach
    } else {//Load XIB cell2
        let placeCell = tableView.dequeueReusableCell(withIdentifier: "cell2") as! XIBCell2

        return placeCell
    }

}

1

这是我的方法:从XIB文件加载自定义UITableViewCells…还有另一种方法

我们的想法是要创建的一个子类SampleCell UITableViewCellIBOutlet UIView *content属性和需要配置从代码中的每个自定义子视图的属性。然后创建一个SampleCell.xib文件。在此nib文件中,将文件所有者更改为SampleCell。添加UIView大小适合您需求的内容。添加并配置所需的所有子视图(标签,图像视图,按钮等)。最后,将内容视图和子视图链接到文件所有者。


1

这是在以下位置注册细胞的通用方法UITableView

protocol Reusable {
    static var reuseID: String { get }
}

extension Reusable {
    static var reuseID: String {
        return String(describing: self)
    }
}

extension UITableViewCell: Reusable { }

extension UITableView {

func register<T: UITableViewCell>(cellClass: T.Type = T.self) {
    let bundle = Bundle(for: cellClass.self)
    if bundle.path(forResource: cellClass.reuseID, ofType: "nib") != nil {
        let nib = UINib(nibName: cellClass.reuseID, bundle: bundle)
        register(nib, forCellReuseIdentifier: cellClass.reuseID)
    } else {
        register(cellClass.self, forCellReuseIdentifier: cellClass.reuseID)
    }
}

说明:

  1. Reusable协议从其类名称生成单元ID。请确保遵循以下约定:cell ID == class name == nib name
  2. UITableViewCell符合Reusable协议。
  3. UITableView 扩展名通过nib或class消除了注册细胞的区别。

用法示例:

override func viewDidLoad() {
    super.viewDidLoad()
    let tableView = UITableView()
    let cellClasses: [UITableViewCell.Type] = [PostCell.self, ProfileCell.self, CommentCell.self]
    cellClasses.forEach(tableView.register)
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: PostCell.self.reuseID) as? PostCell
    ...
    return cell
}

0

我不知道是否有规范的方法,但这是我的方法:

  • 为ViewController创建一个xib
  • 将文件所有者类设置为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]

如果Apple更改Xib中的项目顺序,可能会中断。


对我来说,这总是创建一个新实例。每次出队似乎都返回nil。
很奇怪

0
 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;

0

此扩展要求Xcode7 beta6

extension NSBundle {
    enum LoadViewError: ErrorType {
        case ExpectedXibToExistButGotNil
        case ExpectedXibToContainJustOneButGotDifferentNumberOfObjects
        case XibReturnedWrongType
    }

    func loadView<T>(name: String) throws -> T {
        let topLevelObjects: [AnyObject]! = loadNibNamed(name, owner: self, options: nil)
        if topLevelObjects == nil {
            throw LoadViewError.ExpectedXibToExistButGotNil
        }
        if topLevelObjects.count != 1 {
            throw LoadViewError.ExpectedXibToContainJustOneButGotDifferentNumberOfObjects
        }
        let firstObject: AnyObject! = topLevelObjects.first
        guard let result = firstObject as? T else {
            throw LoadViewError.XibReturnedWrongType
        }
        return result
    }
}

创建一个Xib文件,该文件仅包含1个自定义UITableViewCell。

加载它。

let cell: BacteriaCell = try NSBundle.mainBundle().loadView("BacteriaCell")

0
 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cellReuseIdentifier = "collabCell"
            var cell:collabCell! = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as? collabCell
            if cell == nil {
                tableView.register(UINib(nibName: "collabCell", bundle: nil), forCellReuseIdentifier: cellReuseIdentifier)
                cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! collabCell!
            }


            return cell

}
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.