views:

255

answers:

1

Why can't I add a subview to table view cell's content view?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellTableIdentifier = @"CellTableIdentifier ";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellTableIdentifier];
    if (cell == nil) 
    {
        cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellTableIdentifier];
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 5, 70, 15)];
        label.text=@"Name:";
        [cell.contentView addSubview:label];
    }
    return [cell autorelease];

}
+2  A: 

It should be a problem of memory management.

Consider this statement:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellTableIdentifier];

According to the Cocoa memory management rule, this is not an alloc/new/copy method, i.e. you don't own the cell, so you should not -release it after finish using it. However, the next statement (assume cell != nil):

return [cell autorelease];

will make the cell be released (some time later), causing a double-release of the cell (some time later). Therefore you should simply return cell;.

Now what if cell == nil? Inside the if branch, you wrote

    cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellTableIdentifier];

Since the cell is created with alloc, you are responsible to -release it. But since you're going to return it to others, you have to relinquish the ownership while avoid it not being deallocated immediately. This is where -autorelease is used, to temporarily transfer the ownership to an "autorelease pool" so other code can have a chance to retake the ownership (-retain it) before it got flushed into voidness.

In the other words you should replace this statement with cell = [[[...] autorelease];.

Similarly, you should -release the label because it is -alloc-ed and you are no longer own it. However, you don't need to -autorelease because you are sure there is already another owner (cell.contentView).

To summarize, you should rewrite the code as:

 static NSString *CellTableIdentifier = @"CellTableIdentifier ";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellTableIdentifier];
if (cell == nil) 
{
    cell=[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellTableIdentifier] autorelease];
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 5, 70, 15)];
    label.text=@"Name:";
    [cell.contentView addSubview:label];
    [label release];
}
return cell;

BTW, you can use UITableViewCellStyleValue2 (like the address book) to avoid messing with the view hierarchy.

KennyTM