views:

75

answers:

2

Hi, In my program I'm creating a couple of custom UIViewCells loaded from a nib file:

[[NSBundle mainBundle] loadNibNamed:@"CustomCells" owner:self options:nil];

Once they're loaded i set them up and return from the function:

if (indexpath.row == 1) {
    [nibTextInputer setupWithName:@"notes" ...];
    return nibTextInputer;
} else {
    [nibSelectInputer setupWithName:@"your_choice" ...];
    return nibSelectInputer;
};

Where nibTextInputer is of my class (AFTextInputer) and nibSelectInputer is of my other class (AFTextInputer). Both classes subclass from UITableViewCell.

It all works fine, BUT breaks when I add caching to that:

Boolean inCache = false;
if (indexPath.row == 1) {
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"nibTextInputer"];
   if (cell != nil) {
      NSLog(@"%@", [cell description]); // prints out ok, correct type.
      nibTextInputer = (AFTextInputer*) cell;
      inCache = true;
   };
};

if (!inCache) {
    [[NSBundle mainBundle] loadNibNamed:@"CustomCells" owner:self options:nil];
}

Once I add the above EXC_BAD_ACCESS starts appearing in random places, usually with no additional information and sometimes with this error:

-[CALayer prepareForReuse]: unrecognized selector sent to instance

or even

-[UIImage prepareForReuse]: unrecognized selector sent to instance

The location of EXC_BAD_ACCESS is seemingly random. Sometimes it's right after "dequeue", sometimes outside of the function..

I guess the problem lies within my implementation of custom UIViewCells, but I have no idea where to start looking..

Ideas?

+1  A: 

You have an over-release occurring on your UITableViewCell. -[UITableViewCell prepareForReuse] is called just before returning from -[UITableView dequeueReusableCellWithIdentifier:], but when it is being called the cell is no longer there but instead a CALayer, UIImage or something that you don't have access to.

The problem is likely in the way you are loading the custom cell. For what it's worth, this is how I typically do it:

static NSString *CellIdentifier = @"CustomCell"; // This string should also be set in IB

CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    cell = nibCell; // nibCell is a retained IBOutlet which is wired to the cell in IB
}

// Set up the cell...
Cory Kilger
A: 

This is probably where you're going to run into problems:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"nibTextInputer"];

The UITableView class lumps all of your cells into the same pool for reuse; it doesn't know that some cells are one kind of subclass (i.e. AFTextInputer) and some cells are another kind of subclass (i.e. AFTextInputer). So when you dequeue a cell in the if (indexPath.row == 1) block, you might be getting the wrong kind of subclassed cell back. The "identifier" is just a string that indicates to the built-in cache which table's cells you're referencing; it doesn't actually use that string to dig into the cache to find an object with a matching subclass name.

P.S. Why are you using a type called Boolean instead of the "built-in" BOOL?

Shaggy Frog
that's what ..CellWithIdentifier: is for - the identifier ("nibTextInputer") is set up in nib file and I double checked by NSLogging the type of cell.
Merlin
I have no idea what's the difference wetween Boolean and BOOL.. I'll look into that, thanks.
Merlin