How do you load custom UITableViewCells from Xib files? How do you load custom UITableViewCells from Xib files? ios ios

How do you load custom UITableViewCells from Xib files?


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


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

See the actual post for more details. I prefer method #2 as it seems simpler.

Method #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:

- (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. It used to be in the official docs but is now removed in favor of storyboards.

I posted a working example on Github:
https://github.com/bentford/NibTableCellExample

edit for 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}


Register

After iOS 7, this process has been simplified down to (swift 3.0):

// For registering nib filestableView.register(UINib(nibName: "MyCell", bundle: Bundle.main), forCellReuseIdentifier: "cell")// For registering classestableView.register(MyCellClass.self, forCellReuseIdentifier: "cell")

(Note) This is also achievable by creating the cells in the .xib or .stroyboard files, as prototype cells. If you need to attach a class to them, you can select the cell prototype and add the corresponding class (must be a descendant of UITableViewCell, of course).

Dequeue

And later on, dequeued using (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}

The difference being that this new method not only dequeues the cell, it also creates if non-existant (that means that you don't have to do if (cell == nil) shenanigans), and the cell is ready to use just as in the example above.

(Warning) tableView.dequeueReusableCell(withIdentifier:for:) has the new behavior, if you call the other one (without indexPath:) you get the old behavior, in which you need to check for nil and instance it yourself, notice the UITableViewCell? return value.

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

And of course, the type of the associated class of the cell is the one you defined in the .xib file for the UITableViewCell subclass, or alternatively, using the other register method.

Configuration

Ideally, your cells have been already configured in terms of appearance and content positioning (like labels and image views) by the time you registered them, and on the cellForRowAtIndexPath method you simply fill them in.

All together

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

And of course, this is all available in ObjC with the same names.