天天看點

如何從Xib檔案加載自定義UITableViewCells?

本文翻譯自:How do you load custom UITableViewCells from Xib files?

The question is simple: How do you load custom

UITableViewCell

from Xib files?

問題很簡單:如何從Xib檔案加載自定義

UITableViewCell

Doing so allows you to use Interface Builder to design your cells.

這樣做允許您使用Interface Builder來設計單元格。

The answer apparently is not simple due to memory managment issues.

由于記憶體管理問題,答案顯然并不簡單。

This thread mentions the issue and suggests a solution, but is pre NDA-release and lacks code.

這個主題提到了這個問題并建議了一個解決方案,但是在NDA釋出之前并且沒有代碼。

Here's a long thread that discusses the issue without providing a definitive answer.

這是一個很長的線程 ,在沒有提供明确答案的情況下讨論了這個問題。

Here's some code I've used:

這是我用過的一些代碼:
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];
}
           

To use this code, create MyCell.m/.h, a new subclass of

UITableViewCell

and add

IBOutlets

for the components you want.

要使用此代碼,請建立MyCell.m / .h,

UITableViewCell

的新子類,并為所需的元件添加

IBOutlets

Then create a new "Empty XIB" file.

然後建立一個新的“空XIB”檔案。

Open the Xib file in IB, add a

UITableViewCell

object, set its identifier to "MyCellIdentifier", and set its class to MyCell and add your components.

在IB中打開Xib檔案,添加

UITableViewCell

對象,将其辨別符設定為“MyCellIdentifier”,并将其類設定為MyCell并添加元件。

Finally, connect the

IBOutlets

to the components.

最後,将

IBOutlets

連接配接到元件。

Note that we did not set the File's Owner in IB.

請注意,我們沒有在IB中設定檔案所有者。

Other methods advocate setting the File's Owner and warn of memory leaks if the Xib is not loaded via an additional factory class.

如果未通過其他工廠類加載Xib,則其他方法主張設定檔案所有者并警告記憶體洩漏。

I tested the above under Instruments/Leaks and saw no memory leaks.

我在Instruments / Leaks下測試了上面的内容,沒有發現記憶體洩漏。

So what's the canonical way to load cells from Xibs?

那麼從Xibs加載單元格的規範方法是什麼?

Do we set File's Owner?

我們設定檔案的所有者嗎?

Do we need a factory?

我們需要工廠嗎?

If so, what's the code for the factory look like?

如果是這樣,工廠的代碼是什麼樣的?

If there are multiple solutions, let's clarify the pros and cons of each of them...

如果有多種解決方案,讓我們澄清每種解決方案的優缺點......

#1樓

參考:https://stackoom.com/question/2gzf/如何從Xib檔案加載自定義UITableViewCells

#2樓

The correct way to do it is to create a UITableViewCell subclass implementation, header, and XIB.

正确的方法是建立UITableViewCell子類實作,标頭和XIB。

In the XIB remove any views and just add a table cell.

在XIB中删除任何視圖,隻需添加一個表格單元格。

Set the class as the name of the UITableViewCell subclass.

将類設定為UITableViewCell子類的名稱。

For file owner, make it the UITableViewController subclass class name.

對于檔案所有者,使其成為UITableViewController子類的類名。

Connect the file owner to the cell using the tableViewCell outlet.

使用tableViewCell插座将檔案所有者連接配接到單元。

In the header file:

在頭檔案中:
UITableViewCell *_tableViewCell;
@property (assign) IBOutlet UITableViewCell *tableViewCell;
           

In the implementation file:

在實作檔案中:
@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樓

The right solution is this:

正确的解決方案是:
- (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;
}
           

#4樓

Check this - http://eppz.eu/blog/custom-uitableview-cell/ - really convenient way using a tiny class that ends up one line in controller implementation:

檢查一下 - http://eppz.eu/blog/custom-uitableview-cell/ - 使用一個在控制器實作中結束一行的小類非常友善的方法:
-(UITableViewCell*)tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
    return [TCItemCell cellForTableView:tableView
                          atIndexPath:indexPath
                      withModelSource:self];
}
           
如何從Xib檔案加載自定義UITableViewCells?

#5樓

I've decided to post since I don't like any of these answers -- things can always be more simple and this is by far the most concise way I've found.

我決定發帖,因為我不喜歡任何這些答案 - 事情總是更簡單,這是迄今為止我發現的最簡潔的方式。

1. Build your Xib in Interface Builder as you like it

1.根據需要在Interface Builder中建構Xib
  • Set File's Owner to class NSObject 将File的Owner設定為NSObject類
  • Add a UITableViewCell and set its class to MyTableViewCellSubclass -- if your IB crashes (happens in Xcode > 4 as of this writing), just use a UIView of do the interface in Xcode 4 if you still have it laying around 添加一個UITableViewCell并将其類設定為MyTableViewCellSubclass - 如果您的IB崩潰(在撰寫本文時Xcode> 4中發生),隻需使用UIView在Xcode 4中執行該接口,如果您仍然存在它
  • Layout your subviews inside this cell and attach your IBOutlet connections to your @interface in the .h or .m (.m is my preference) 在此單元格内布置子視圖,并将您的IBOutlet連接配接附加到.h或.m中的@interface(.m是我的偏好)

2. In your UIViewController or UITableViewController subclass

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. In your MyTableViewCellSubclass

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

    return self;
}
           

#6樓

Here are two methods which the original author states was recommended by an IB engineer .

以下是IB工程師推薦的兩種原始作者所述的方法。

See the actual post for more details.

有關詳細資訊,請參閱實際文章。

I prefer method #2 as it seems simpler.

我更喜歡方法#2,因為它似乎更簡單。

Method #1:

方法#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;
}
           

Method #2:

方法#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;
}
           

Update (2014): Method #2 is still valid but there is no documentation for it anymore.

更新(2014):方法#2仍然有效,但不再有文檔。

It used to be in the official docs but is now removed in favor of storyboards.

它曾經在官方文檔中,但現在被删除,有利于故事闆。

I posted a working example on Github:

我在Github上釋出了一個工作示例:

https://github.com/bentford/NibTableCellExample

https://github.com/bentford/NibTableCellExample

edit for Swift 4.2

編輯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
}