Sometimes the standard UITableViewCells don’t cut it and you need to create your own.

Here’s how you can create your own UITableViewCell in Xcode and format it however your like.

1. Create UITableView xib file.

After creating a xib project, and dragging in a UITableView

create a new xib file for your UITableViewCell

and call it CustomCell.xib.

Delete the view that it gives you and instead drag out a ‘Table View Cell’ from the utilities area.

Now, it’s in here where we are free to do whatever kind of layout we want. In this case I am going to layout two labels in the middle on top of each other, like this:

2. Create a custom class.

I am going to need some code to back this xib file up, so next we create an objective-c class that extends UITableViewCell.

and I am going to give it the same name as my xib – CustomCell.

3. Tie class to xib.

Now to we need to connect this class to the xib. We do by clicking on our cell xib Identity Inspector and typing in our class name as below:

4. Create some properties.

With those two connected, we now need to create some properties for the elements in our UITableViewCell xib. Do this like you would any other property, by control dragging the elements from the xib to the custom class.

Note: I also added a reuseIdentifier class method here with an implementation that looks like this:

CustomCell.m

+ (NSString *)reuseIdentifier {    
    return @"CustomCellIdentifier";
}

We’ll use this later.

5. Tie it to the parent class.

Now we need to associate this xib with the parent VC xib that is going to use it. Do that by clicking the yellow cube on the left called ‘Files Owner’, the ‘Inspector’ tab in utilities, and then typing the VC file name (in this case I just used the default VC creating for me with the initial project).

6. Create a property for the cell in the parent.

In the ViewController with the UITableView that is going to be using this cell, add property pointing to it like so:

ViewController.h

#import <UIKit/UIKit.h>
#import "CustomCell.h"

@interface ViewController : UIViewController
@property (assign, nonatomic) IBOutlet CustomCell *customCell;

@end

ViewController.m

@synthesize customCell = _customCell;

Do this by bringing up your xib and the assistant for it, and dragging the cell over like any other control.

7. Connect this property to the cell.

This part is a bit weird, but now we go back to our custom cell xib, and connect our cell to the parent property in the View Controller.

Do this by clicking that ‘Files Owner’ yellow cube on the side, and then the ‘Connections Inspector’ circle with an arrow in it on the right. You should now see the customCell property we just defined in the parent VC.

Click on the little grey circle beside the customCell in the outlets section, and drag it to the cell. This connects the cell to the parent property.

8. Add a UITableView property to VC.

ViewController.h

@property (strong, nonatomic) IBOutlet UITableView *tableView;

ViewController.m

@synthesize tableView = _tableView;

9. Hook up UITableView datasource and delegate.

Last but not least we need to tell our UITableView that our ViewController is going to act as it’s datasource and delegate.

Go back to the ViewController xib, select the UITableView element, and from the ‘Connections Inspector’ drag those little circles out again beside dataSource and delegate to the yellow cube ‘Files Owner’ (not the UITableView!).


You will know you have it hooked up right when you see ‘File’s Owner’ beside the dataSource delegate outlets.

10. Implement the datasource delegate methods.

In your ViewController, implement the necessary UITableView datasource delegate methods.

ViewController.m

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:[CustomCell reuseIdentifier]];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        cell = _customCell;
        _customCell = nil;
    }        
    
    cell.topLabel.text = @"I am on top";
    cell.bottomLabel.text = @"and I'm on the bottom";
    
    return cell;     
}

10.b. Set cell reuse identifier

Update

As Ryan pointed out down in the comments section, we need to set the reuse identifier on our UITableViewCell, so it will get pooled and reused propertly in the pool.

Click on your table view cells, go to the attributes inspector and make sure the text you enter there matches the identifier in your UITableCell class. Else as Eric points out, our cells won’t get reused properly.

11. Fire it up!

Run the app in the simulator and you should now see something like this:



I also added one line to the viewDidLoad() to adjust for row height:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // make row height same as our xib to get 
    // rid of the appearance of multpile rows
    self.tableView.rowHeight = 125;
}

Big thanks to Jeremy Gale for showing me the in’s and out’s of hooking up UITableViewCells to xibs.

Here’s a complete listing of files:

CustomCell.h

#import <UIKit/UIKit.h>

@interface CustomCell : UITableViewCell
+ (NSString *)reuseIdentifier;
@property (strong, nonatomic) IBOutlet UILabel *topLabel;
@property (strong, nonatomic) IBOutlet UILabel *bottomLabel;
@end

CustomCell.m

#import "CustomCell.h"

@implementation CustomCell
@synthesize topLabel;
@synthesize bottomLabel;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

+ (NSString *)reuseIdentifier {    
    return @"CustomCellIdentifier";
}

@end

ViewController.h

#import "CustomCell.h"

@implementation CustomCell
@synthesize topLabel;
@synthesize bottomLabel;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

+ (NSString *)reuseIdentifier {    
    return @"CustomCellIdentifier";
}

@end

ViewController.m


#import "ViewController.h"
#import "CustomCell.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize customCell = _customCell;
@synthesize tableView = _tableView;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:[CustomCell reuseIdentifier]];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        cell = _customCell;
        _customCell = nil;
    }        
    
    cell.topLabel.text = @"I am on top";
    cell.bottomLabel.text = @"and I'm on the bottom";
    
    return cell;     
}


- (void)viewDidLoad
{
    [super viewDidLoad];
    // make row height same as our xib to get 
    // rid of the appearance of multpile rows
    self.tableView.rowHeight = 125;
}

- (void)viewDidUnload
{
    [self setTableView:nil];
    [super viewDidUnload];
}

@end

Bonus – how to create a new xib and ViewController

1. Create new xib.

2. Create new ViewController class.

3. Drag out display elements onto xib.

4. Connect the File Owner to the view.

We want the File Owner view outlet to be connected to the xib view.
Do this by clicking view owner, clicking the grey circle beside view, and then dragging the circle to the view on screen.

5. Connect display elements to File’s Owner

You need to connect each display element in your xib to your parent ViewController.

This is done by clicking the yellow cube ‘File’s Owner’ icon and dragging little grey circle beside it’s property to the yellow cube line.

When you are done you should be able to mouse over each outlet and see the corresponding element light up in your xib.