views:

10718

answers:

10

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?

+10  A: 

Just implement a method with the appropriate method signature:

- (NSString *) reuseIdentifier {
  return @"myIdentifier";
}
Louis Gerbarg
A: 

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

August
That's odd. At least two of the talks at the NY talk had demo code that used cells created in IB.
Shawn Craver
Not sure I believe this since they use IB to create cells in Apple's Advanced Table View Cells example project.
iWasRobbed
Thanks for that. Every time I've done it I've run into problems. This could be why
skorulis
+6  A: 

Look at the answer I gave to this question:

http://stackoverflow.com/questions/202471/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.

Kendall Helmstetter Gelner
You shouldn't make table view cells in IB if you need transparency and want good scrolling performance. For certain UIs, you need transparency (to render text over graphics e.g.). Sometimes the only way to achieve good scrolling on older (pre-A4) hardware is to render in code, to avoid the GPU having to composite multiple transparent layers.
Nick Forge
True, but even with that you might be better off letting performance suffer slightly on old devices for the easier maintainability of cells built in IB. You can also use this technique as a template cell that you then draw elements from to avoid compositing with a custom draw method.
Kendall Helmstetter Gelner
+1  A: 

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;
}
gustavogb
+27  A: 
Tim Keating
+6  A: 
jrainbow
A: 

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.

sww
A: 

A while back I found a great blog post on this topic at blog.atebits.com, and have since started using Loren Brichter ABTableViewCell class to do all of my UITableViewCells.

You end up with a simple container UIView to put all of your widgets, and scrolling is lightning fast.

Hope this is useful.

eric
A: 

The gustavogb solution doesn't work for me, what I tried is :

ChainesController *c = [[ChainesController alloc] initWithNibName:@"ChainesController" bundle:nil];
[[NSBundle mainBundle] loadNibNamed:@"ChaineArticleCell" owner:c options:nil];
cell = [c.blogTableViewCell retain];
[c release];

It seems to work. The blogTableViewCell is the IBOutlet for the cell and ChainesController is the file's owner.

groumpf
+1  A: 

This technique also works and doesn't require a funky ivar in your view controller for memory management. Here, the custom table view cell lives in a xib named "CustomCell.xib".

 static NSData *sLoadedCustomCell = nil;

 cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
 if (cell == nil) 
 {
   if (sLoadedCustomCell == nil) 
   {        
      // Load the custom table cell xib
      // and extract a reference to the cell object returned
      // and cache it in a static to avoid reloading the nib again.

      for (id loadedObject in [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil]) 
      {
        if ([loadedObject isKindOfClass:[UITableViewCell class]]) 
        {
          sLoadedCustomCell = [[NSKeyedArchiver archivedDataWithRootObject: loadedObject] retain];
          break;
        }
    }
    cell = (UITableViewCell *)[NSKeyedUnarchiver unarchiveObjectWithData: sLoadedCustomCell];
  }
Bill Garrison