Search code examples
iosuitableviewuiscrollviewnsstring

create UITableViewCell programmatically


I am trying to create a UITableViewCell that contains a UIScrollView that is able to scroll horizontally for each cell in the UITableView.

Everything shows correctly and works well. However, when I scroll constantly up and down on the UITableView, memory usage goes up and up and up and up..... which I think means that I am constantly adding the custom elements over each over when the UITableViewCell is being reused. I would like to know how I can stop this from happening.

Here is my code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Configure the cell...
    NSDictionary *cellDictionary = [xmlMArray objectAtIndex:indexPath.row];

    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    // code
    codeString = [[UILabel alloc] initWithFrame:CGRectMake(15.0, 0.5, 70.0, 40.0)];
    codeString.text = [cellDictionary objectForKey:@"Code"];
    codeString.backgroundColor = [UIColor clearColor];
    // series
    addressString = [[UILabel alloc] initWithFrame:CGRectMake(220.0, 10.5, addressString.frame.size.width, 50.0)];
    addressString.text = [NSString stringWithFormat:@"PC %@: %@",[cellDictionary objectForKey:@"Number"] ,[cellDictionary objectForKey:@"Street"]];
    [addressString sizeToFit]; // Dynamic UILabel width
    addressString.backgroundColor = [UIColor clearColor];

    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    UIScrollView *scrollCell  = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.frame.size.width, cell.frame.size.height)];
    [scrollCell setContentSize:(CGSizeMake((220.0 + addressString.frame.size.width)+15, cell.frame.size.height))];

    [scrollCell addSubview:codeString];
    [scrollCell addSubview:addressString];
    [cell addSubview:scrollCell];

    return cell;
}

Solution

  • There seems to be two problems here. I'll try to explain what's actually happening, but you should follow mbm29414's answer on what to do.

    In the first part of this method, you are asking for a UITableViewCell using the identifier:

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    

    The next part is to check if you received a cell with this call:

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                        reuseIdentifier:CellIdentifier];
    }
    

    This means that if your first line of code DID NOT return a cell-object, then you are instantiating a new one.

    Later on in your method, you are instantiating yet another cell:

    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                    reuseIdentifier:CellIdentifier];
    UIScrollView *scrollCell (...)
    

    This way you might not actually be reusing the cells, I'm not sure. At the very least, it should not be there. You potentionally allocate double the space each time. Remove the last instantiation, and that should probably help a little.

    The other problem, I think, is that you're adding scrollView and UILabels to your cells' subviews. Your circle of life:

    • Create cell
    • Create 2 UILabels
    • Create ScrollView
    • Add labels to ScrollView's subview
    • Add scrollView to Cell's subview
    • Send cell on it's merry way

    When your cell is brought back from the dead during [tableView dequeueReusable..], they still contain the UIScrollView with the UILabel. Your code does not take advantage of that, but rather ignores it. This means that you are adding an ADDITIONAL scrollView with labels into your cell. If you scroll up and down a lot, this means that one single cell can possibly contain 50 different scrollViews, all of them taking the same amount of processing.

    This is what happens next:

    • Get cell from the queue
    • (this cell already contains UIScollView and UILabels)
    • Add new scrollView with labels anyway
    • Send it on it's merry way (now with 2 scrollViews and 4 labels)

    To solve this, you should do as mbm29414 suggested, to make your own subclass of UITableViewCell. That way, you can say cell.codeString.text=@"blah";