views:

95

answers:

3

I've been trying to create a TableViewCell consisting of 2 UILabels in the first row, and another UILabel in the second row.

The layout of frames & labels works correctly in the simulator. However:

1) The height is not dynamically increasing / decreasing with each cell

2) The Table crashes whenever it is scrolled in the simulator

Can someone please explain to me what I'm doing wrong in this code? Can't figure it out.

Here is a picture of the cell I'm trying to create:

Talt text

This is my method for dynamically allocating cell height:

#define CELL_PADDING 10.0f
#define IMAGE_SIDE_SIZE 50.0f
#define LABEL_HEIGHT 14.0f
#define LABELWIDTH_CALLSIGN 160.0f
#define LABELWIDTH_DATE 60.0f
#define LABELWIDTH_USER 160.0f
#define FONT_SIZE 11.0f


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {


    RFFlag *aFlag = [flagList objectAtIndex:[indexPath row]];

    CGSize messageConstraint = CGSizeMake(LABELWIDTH_CALLSIGN + LABELWIDTH_DATE + CELL_PADDING,20000.0f);
    CGSize messageSize = [aFlag.msg.station.callsign sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:messageConstraint lineBreakMode:UILineBreakModeWordWrap];
    CGFloat height = MAX(messageSize.height, 44.0f);

    CGFloat cellHeight = height + LABEL_HEIGHT + (CELL_PADDING * 3);

    return cellHeight;
}

This is my CelLForRowAtIndexPathMethod:

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

        RFFlag *aFlag = [flagList objectAtIndex:[indexPath row]];
        UITableViewCell *cell;
        UILabel *callsign,*dateposted,*message;

        cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

        if (cell == nil) {

            cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"]autorelease];


            callsign = [[UILabel alloc] initWithFrame:CGRectMake(IMAGE_SIDE_SIZE + (CELL_PADDING*2), CELL_PADDING, LABELWIDTH_CALLSIGN, LABEL_HEIGHT)];
            [callsign setMinimumFontSize:FONT_SIZE];
            [callsign setFont:[UIFont systemFontOfSize:FONT_SIZE]];
            [callsign setTag:3];

            [[cell contentView] addSubview:callsign];

            dateposted = [[UILabel alloc] initWithFrame:CGRectMake(CELL_PADDING*3 + IMAGE_SIDE_SIZE + LABELWIDTH_CALLSIGN, CELL_PADDING, LABELWIDTH_DATE, LABEL_HEIGHT)];       
            [dateposted setMinimumFontSize:FONT_SIZE];
            [dateposted setFont:[UIFont systemFontOfSize:FONT_SIZE]];
            [dateposted setTag:2];

            [[cell contentView] addSubview:dateposted];


            message = [[UILabel alloc] initWithFrame:CGRectZero];
            [message setLineBreakMode:UILineBreakModeWordWrap];
            [message setMinimumFontSize:FONT_SIZE];
            [message setNumberOfLines:0];
            [message setFont:[UIFont systemFontOfSize:FONT_SIZE]];
            [message setTag:1];

            [[cell contentView] addSubview:message];

        }
        if (!message)
            message = (UILabel*)[cell viewWithTag:1];



        [message setText:aFlag.msg.messageData];
        [callsign setText:aFlag.msg.station.callsign];
        [dateposted setText:aFlag.msg.createdDate];


        CGSize messageConstraint = CGSizeMake(LABELWIDTH_CALLSIGN + LABELWIDTH_DATE + CELL_PADDING, 20000.0f);
        CGSize messageSize = [aFlag.msg.messageData sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:messageConstraint lineBreakMode:UILineBreakModeWordWrap];
        [message setFrame:CGRectMake(IMAGE_SIDE_SIZE + (CELL_PADDING*2), LABEL_HEIGHT + (CELL_PADDING*2), LABELWIDTH_CALLSIGN + CELL_PADDING + LABELWIDTH_DATE, MAX(messageSize.height,44.0f))];

        return cell;
    }
+1  A: 

One thing your certainly doing wrong is the use of the variables callsign, dateposted and message. Where are these declare?

Once you start scrolling, the iPhone will reuse the cells that are scrolled out of view. In these cases, you don't assign new values to the mentioned variables. They probably refer the object that have just been freed.

I'll need to make these variables local variables of the method. If dequeueReusableCellWithIdentifier: returns an existing table cell, you'll need to dig into the subviews of the cell to locate the three labels and assign them to the variable.s

Codo
A: 

Maybe the height problem is related to the call where you get messageSize, but i can't say more without knowing what is RFFlag.

About the crash i think this happens when a cell is reused: in that case

[callsign setText:aFlag.msg.station.callsign];

is executed but callsign is an uninitialized variable in the stack which could be anything and you try to dispatch a message to it. Same for dateposted.

And btw, when you create the UILabels you're causing a memory leak because you never release them.

Jack
A: 

Is the crash EXC_BAD_ACCESS? If so, try this

  1. Run a Build and Analyze -- is it clean? Take a good look at everything it says.

  2. Run with NSZombiesEnabled: I blogged about how to do that here:

    http://loufranco.com/blog/files/debug-iphone-crash-EXC_BAD_ACCESS.html

    This causes the runtime to not dealloc objects and instead complains if you send messages to objects with 0 retainCount.

Lou Franco