title: Drawing custom UITableCells with the correct data
body: <p>I've got a UITableView with custom tablecells. First I had a version which implemented a separate NIB file to create the custom cell view, but this makes scrolling awfully slow. The official answer is to do your own drawing, so I implemented a drawing variant (<a href="http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview/" rel="nofollow noreferrer">ABTableViewCell</a>).</p>
  
  <p>Everything is working now, except for the drawing of the cells that are out of the view. The first 8 cells are drawn correctly - they get the correct title, image, etc. - but everything outside of that has a random repetition of already drawn cells. Only when the cell is clicked/touched the labels and images of the cell are updated with the correct data.</p>
  
  <p>My RootViewController implements UITableViewDataSource and CustomCell is initialised there.</p>
  
  <p>I've verified that all the data is passed correctly to the CustomCell, so it must have something to do with the drawing. I think I've tracked it down to the fact that the <code>drawContentView</code> method is only called for the cells which are in view and not for the ones that scroll into view. </p>
  
  <p>How would I trigger the drawContentView again to update the cells which come into view? Is that something I would have to do from my RootViewController, using something else than: <code>(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath</code>?</p>
  
  <p>CustomCell.h:</p>
  
  <pre><code>#import "ABTableViewCell.h"
  
  @interface CustomCell : ABTableViewCell {
    NSString * cellSubText;
    NSString * cellText;
    NSString * cellImage;
    NSString * cellIcon;
    NSString * cellId;
  }
  
  @property (nonatomic, copy) NSString *cellSubText;
  @property (nonatomic, copy) NSString *cellText;
  @property (nonatomic, copy) NSString *cellImage;
  @property (nonatomic, copy) NSString *cellIcon;
  @property (nonatomic, copy) NSString *cellId;
  
  @end
  </code></pre>
  
  <p>CustomCell.m:</p>
  
  <pre><code>#import "CustomCell.h"
  
  @implementation CustomCell
  
  @synthesize cellSubText, cellText, cellImage, cellIcon, cellId;
  
  static UIFont *celSubFont = nil;
  static UIFont *cellFont = nil;
  
  + (void)initialize {
      if(self == [CustomCell class]) {
          cellSubFont = [[UIFont systemFontOfSize:13] retain];
          cellFont = [[UIFont boldSystemFontOfSize:17] retain];
      }
  }
  
  - (void)setFirstText:(NSString *)s {
      [cellSubText release];
      cellSubText = [s copy];
      [self setNeedsDisplay]; 
  }
  
  - (void)setLastText:(NSString *)s {
      [cellText release];
      cellText = [s copy];
      [self setNeedsDisplay]; 
  }
  
  - (void)drawContentView:(CGRect)r {
      CGContextRef context = UIGraphicsGetCurrentContext();
  
      UIColor *backgroundColour = [UIColor whiteColor];
      UIColor *categoryColour = [UIColor grayColor];
      UIColor *titleColour = [UIColor blackColor];
    if(self.highlighted || self.selected) {
      backgroundColour = [UIColor clearColor];
          categoryColour = [UIColor whiteColor];
      titleColour = [UIColor whiteColor];
      }
  
      [backgroundColour set];
      CGContextFillRect(context, r);
  
      CGPoint pCategory;
      pCategory.x = 60;
      pCategory.y = 3;
  
      [categoryColour set];
    [cellSubText drawAtPoint:pCategory forWidth:235 withFont:categoryFont minFontSize:13 actualFontSize:NULL lineBreakMode:UILineBreakModeTailTruncation baselineAdjustment:UIBaselineAdjustmentNone];  
  
    CGPoint pTitle;
      pTitle.x = 60;
      pTitle.y = 17;
  
    [titleColour set];
    [cellText drawAtPoint:pTitle forWidth:235 withFont:titleFont minFontSize:17 actualFontSize:NULL lineBreakMode:UILineBreakModeTailTruncation baselineAdjustment:UIBaselineAdjustmentNone];  
  
    //Display the image
    CGPoint pImage;
      pImage.x = 5;
      pImage.y = 5;
  
    NSData *imageData = [[NSData dataWithContentsOfURL:[NSURL URLWithString:cellImage]] retain];
    UIImage *image = [UIImage imageWithData:imageData];
    [image drawAtPoint:pImage];
  }
  
  - (void)dealloc {
    [cellSubText release];
    [cellText release];
    [cellIcon release];
    [cellImage release];
    [super dealloc];
  }
  @end
  </code></pre>
  
  <p>RootViewController.m</p>
  
  <pre><code>#import "CustomCell.h"
  #import "MyAppDelegate.h"
  #import "RootViewController.h"
  #import "DetailViewController.h"
  
  @implementation RootViewController
  @synthesize tableDataArray;
  
  - (void)viewDidLoad {
    [super viewDidLoad];
  }
  
  //Override the default initWithNibName method
  - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil tableDataSource:(NSArray*)tableData {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
      // Custom initialization
      tableDataArray = [tableData retain];   
    }
    return self;
  }
  
  -(void)viewWillAppear:(BOOL)animated {
    appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];    
    [super viewWillAppear:animated];
  }
  
  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.tableDataArray count];
  }
  
  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      static NSString *CustomCellIdentifier = @"CustomCellIdentifier";
  
      CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
      if(cell == nil) {
          cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CustomCellIdentifier] retain];
      }
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    NSUInteger row = [indexPath row];
    NSDictionary *rowData = [self.tableDataArray objectAtIndex:row];
      cell.cellSubText = [rowData objectForKey:@"Date"];
      cell.cellText = [rowData objectForKey:@"Name"];
    cell.cellImage = [rowData objectForKey:@"Image"];
    cell.cellId = [rowData objectForKey:@"Id"];
  
      return cell;
  }
  
  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    NSString *selectedCell = [tableDataArray objectAtIndex:indexPath.row];
  
    DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailView" bundle:[NSBundle mainBundle]];
    detailViewController.selectedCell = selectedCell;
    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
    detailViewController = nil;
  }
  
  - (void)dealloc { 
      [super dealloc];
  }
  
  @end
  </code></pre>