hanumanDev
hanumanDev

Reputation: 6614

How to optimize cellForRowAtIndexPath: code

After adding a font and a shadow to some UILabels I noticed that the table view animation lags when the view is popped off the stack (a side swipe like FB/Path uses). The side swipe was smooth until I added the UILabel shadows.

I think I might be adding it it the wrong place so that the label properties are being added incorrectly maybe. Please take a look at the following cellForRowAtIndexPath: method below:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * cellReuseIdentifier = @"cellReuseIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];

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

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 2, self.view.bounds.size.width, 200)];
    imageView.image = [UIImage imageNamed:@"rest.jpg"];
    [cell.contentView addSubview:imageView];

    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 2, 320, 30)];

    titleLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:@"title"];
    titleLabel.backgroundColor = [UIColor clearColor];

    titleLabel.textColor = [UIColor whiteColor];
    [titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:24]];
    titleLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
    titleLabel.layer.shadowOpacity = 0.7;

    [cell.contentView addSubview:titleLabel];

    UILabel *detailLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, cell.bounds.size.width, 30)];

    detailLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:@"description"];
    detailLabel.backgroundColor = [UIColor clearColor];

    detailLabel.textColor = [UIColor whiteColor];
    [detailLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18]];
    detailLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
    detailLabel.layer.shadowOpacity = 0.7;

    [cell.contentView addSubview:detailLabel];

    cell.contentView.backgroundColor = [UIColor clearColor];


    return cell;
}

thanks for any help.

Upvotes: 0

Views: 946

Answers (6)

Johannes Fahrenkrug
Johannes Fahrenkrug

Reputation: 44808

This article from Twitter Engineering gives you a great overview: http://engineering.twitter.com/2012/02/simple-strategies-for-smooth-animation.html

Basically, you want to avoid using subviews but instead draw your content directly with Quartz. It's the single best thing you can do to improve performance. Also: Avoid transparency! In Instruments, you can also use the Core Animation instrument and activate "Color Blended Layers" to see where transparent views are being composed:

enter image description here

Upvotes: 1

lithewall
lithewall

Reputation: 66

You need create custom table view cell with a class. This code you added many label then shadow show no correctly. code like this.

(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * cellReuseIdentifier = @"cellReuseIdentifier"; UITableCustomViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];

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

cell.imageView.image = [UIImage imageNamed:@"rest.jpg"];

cell.titleLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:@"title"];

cell.detailLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:@"description"];

return cell;

}

Upvotes: 0

Nishant Tyagi
Nishant Tyagi

Reputation: 9913

Replace your code with this :

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * cellReuseIdentifier = @"cellReuseIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];

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


        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 2, self.view.bounds.size.width, 200)];
        imageView.image = [UIImage imageNamed:@"rest.jpg"];
        imageView.tag =1;
        [cell.contentView addSubview:imageView];

        UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 2, 320, 30)];

        titleLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:@"title"];
        titleLabel.backgroundColor = [UIColor clearColor];
        titleLabel.tag = 2;
        titleLabel.textColor = [UIColor whiteColor];
        [titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:24]];
        titleLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
        titleLabel.layer.shadowOpacity = 0.7;

        [cell.contentView addSubview:titleLabel];

        UILabel *detailLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, cell.bounds.size.width, 30)];
        detailLabel.tag = 3;
        detailLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:@"description"];
        detailLabel.backgroundColor = [UIColor clearColor];

        detailLabel.textColor = [UIColor whiteColor];
        [detailLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18]];
        detailLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
        detailLabel.layer.shadowOpacity = 0.7;


    }

    UIImageView *tempImgView = (UIImageView *)[cell viewWithTag:1];
    tempImgView.image = [UIImage imageNamed:@""];// Here you can set any image by reusing imageview without allocating again and again

    UILabel *tempLabel;

    tempLabel = (UILabel *)[cell viewWithTag:2];
    tempLabel.text = @"";// Here you can access your title label and can set its properties without allocating again

    tempLabel = (UILabel *)[cell viewWithTag:3];
    tempLabel.text = @"";// Here you can access your detailLabel label and can set its properties without allocating again


     [cell.contentView addSubview:detailLabel];

    cell.contentView.backgroundColor = [UIColor clearColor];


    return cell;
}

Upvotes: 0

Marcel
Marcel

Reputation: 6579

You add subviews, even after dequeueing instead of initializing a new cell. Make sure all the code that creates and adds subviews are only done on initializing a cell. If you need to refer to views in the cell for configuring, subclass UITableViewCell.

Also, shadow rendering could be slowing it down too, add a shadowpath to make the rendering more efficient:

add to your tableView:cellForRowAtIndexPath: method:

...
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:detailLabel.layer.bounds].CGPath;
detailLabel.layer.shadowPath = shadowPath;
...

Upvotes: 1

Wain
Wain

Reputation: 119031

You're always adding new subviews. So whenever you scroll the table view your cells are getting more and more content added into them.

Create all your subviews when the cell is created and then just update the subviews settings. Something like:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * cellReuseIdentifier = @"cellReuseIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];

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

        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 2, self.view.bounds.size.width, 200)];
        imageView.tag = 123123;
        [cell.contentView addSubview:imageView];

        UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 2, 320, 30)];

        titleLabel.tag = 234234];
        titleLabel.backgroundColor = [UIColor clearColor];

        titleLabel.textColor = [UIColor whiteColor];
        [titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:24]];
        titleLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
        titleLabel.layer.shadowOpacity = 0.7;

        [cell.contentView addSubview:titleLabel];

        UILabel *detailLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, cell.bounds.size.width, 30)];

        detailLabel.tag = 345345];
        detailLabel.backgroundColor = [UIColor clearColor];

        detailLabel.textColor = [UIColor whiteColor];
        [detailLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18]];
        detailLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
        detailLabel.layer.shadowOpacity = 0.7;

        [cell.contentView addSubview:detailLabel];

        cell.contentView.backgroundColor = [UIColor clearColor];
    }

    UIImageView *imageView = (UIImageView *)[cell viewWithTag:123123];
    imageView.image = [UIImage imageNamed:@"rest.jpg"];

    UILabel *titleLabel = (UILabel *)[cell viewWithTag:234234];
    titleLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:@"title"];

    UILabel *detailLabel = (UILabel *)[cell viewWithTag:345345];
    detailLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:@"description"];

    return cell;
}    

Upvotes: 4

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726879

Since text attributes never change, move the code that sets them inside the if statement. Keep only the code that sets the image and the text of your labels outside the if statement. Cells are reused, so the attributes such as font etc. will remain with the cell even after it gets "recycled". In the else branch add code that finds existing labels in the cell. Otherwise, you keep adding the same label to the cell multiple times.

Upvotes: 1

Related Questions