views:

362

answers:

2

Hi,

I keep getting a crash when loading a UITableView. I am trying to use a cell defined in a nib file.

I have an IBOutlet defined in the view controller header file:

UITableViewCell *jobCell;
@property (nonatomic, assign) IBOutlet UITableViewCell *jobCell;

This is synthesised in the implementation file.

I have a UITableViewCell created in IB and set it's identifier to JobCell.

Here is the cellForRowAtIndexPath method:

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

static NSString *cellIdentifier = @"JobCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
    [[NSBundle mainBundle] loadNibNamed:@"JobsRootViewController" owner:self options:nil];
    cell = jobCell;
    self.jobCell = nil;
}

// Get this job
Job *job = [fetchedResultsController objectAtIndexPath:indexPath];

// Job title
UILabel *jobTitle;
jobTitle = (UILabel *)[cell viewWithTag:tagJobTitle];
jobTitle.text = job.title;

// Job due date
UILabel *dueDate;
dueDate = (UILabel *)[cell viewWithTag:tagJobDueDate];
dueDate.text = [self.dateFormatter stringFromDate:job.dueDate];

// Notes icon
UIImageView *notesImageView;
notesImageView = (UIImageView *)[cell viewWithTag:tagNotesImageView];
if ([job.notes length] > 0) {
    // This job has a note attached to it - show the notes icon
    notesImageView.hidden = NO;
}
else {
    // Hide the notes icon
    notesImageView.hidden = YES;
}

// Job completed button

// Return the cell
return cell;

}

When I run the app - I get a hard crash and the console reports the following:

objc[1291]: FREED(id): message style sent to freed object=0x4046400

I have hooked up all the outlets in IB correctly. What is the issue?

Thanks,

A: 

Your problem is in this block:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
    [[NSBundle mainBundle] loadNibNamed:@"JobsRootViewController" owner:self options:nil];
    cell = jobCell; <- THIS IS A SHALLOW COPY
    self.jobCell = nil; <- YOU JUST RELEASED IT
}

// Get this job
Job *job = [fetchedResultsController objectAtIndexPath:indexPath];

// Job title
UILabel *jobTitle;
jobTitle = (UILabel *)[cell viewWithTag:tagJobTitle]; <- CELL ISNT THERE ANYMORE

You're creating jobCell as an assigned property. The synthesized setter that you use when you say self.jobCell = nil releases the object that you just made cell reference. Make a deep copy instead, or don't set jobCell to nil.

saramah
Commenting out:self.jobCell = nil;Makes no difference - I still get the same crash and error.
Garry
Hm, the problem must be elsewhere in your code then. Try figuring out what you're sending a message to with NSZombieEnabled. Then figure out where in your code you're sending that particular message. Then figure out where you're accidentally releasing the object that you're sending a message to.
saramah
self.jobCell = nil; doesn't release the cell. It simply makes the jobCell pointer point to nil and creates a memory leak if that was the last pointer to that cell. `[self.jobCell release]` will release it.
Brock Woolf
A: 

The easiest way to do this is to break it up into two separate nib files and load the cell from the cell's own nib. Something to note is that you cannot set outlets like this, if you want to do that, you will need a custom UITableViewCell subclass. But if you are not wiring up anything in the cell, you can simply do this:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
    cell = [[[NSBundle mainBundle] loadNibNamed:@"JobsRootViewCell" owner:nil options:nil] objectAtIndex:0];
}
Jason Coco