Loading a Reusable UITableViewCell from a Nib

Viewed 89871

I am able to design custom UITableViewCells and load them just fine using the technique described in the thread found at http://forums.macrumors.com/showthread.php?t=545061. However, using that method no longer allows you to init the cell with a reuseIdentifier which means you have to create whole new instances of each cell at every call. Has anyone figured out a good way to still cache particular cell types for reuses, but still be able to design them in Interface Builder?

16 Answers

Actually, since you are building the cell in Interface Builder, just set the reuse identifier there:

IB_reuse_identifier

Or if you are running Xcode 4, check the Attributes inspector tab:

enter image description here

(Edit: After your XIB is generated by XCode, it contains an empty UIView, but we need a UITableViewCell; so you have to manually remove the UIView and insert a Table View Cell. Of course, IB will not show any UITableViewCell parameters for a UIView.)

Just implement a method with the appropriate method signature:

- (NSString *) reuseIdentifier {
  return @"myIdentifier";
}

Now, in iOS 5 there is an appropriate UITableView method for that:

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

I can't remember where I found this code originally, but it's been working great for me so far.

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"CustomTableCell";
    static NSString *CellNib = @"CustomTableCellView";

    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
        cell = (UITableViewCell *)[nib objectAtIndex:0];
    }

    // perform additional custom work...

    return cell;
}

Example Interface Builder setup...

alt text

Look at the answer I gave to this question:

Is it possible to design NSCell subclasses in Interface Builder?

It's not only possible to design a UITableViewCell in IB, it's desirable because otherwise all of the manual wiring and placement of multiple elements is very tedious. Performaance is fine as long as you are careful to make all elements opaque when possible. The reuseID is set in IB for the properties of the UITableViewCell, then you use the matching reuse ID in code when attempting to dequeue.

I also heard from some of the presenters at WWDC last year that you shouldn't make table view cells in IB, but it's a load of bunk.

Louis method worked for me. This is the code I use to create the UITableViewCell from the nib:

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

    if (cell == nil) 
    {
        UIViewController *c = [[UIViewController alloc] initWithNibName:@"CustomCell" bundle:nil];
        cell = (PostCell *)c.view;
        [c release];
    }

    return cell;
}

I create my custom view cells in a similar manner - except I connect the cell through an IBOutlet.

The [nib objectAt...] approach is susceptible to changes to positions of items in the array.

The UIViewController approach is good - just tried it, and it works nice enough.

BUT...

In all cases the initWithStyle constructor is NOT called, so no default initialisation is done.

I have read various places about using initWithCoder or awakeFromNib, but no conclusive evidence that either of these is the right way.

Apart from explicitly calling some initialization method in the cellForRowAtIndexPath method I haven't found an answer to this yet.

For what it's worth, I asked an iPhone engineer about this at one of the iPhone Tech Talks. His answer was, "Yes, it's possible to use IB to create cells. But don't. Please, don't."

Related