Search code examples
iosuitableviewcgrectmake

How can I speed up a UITableView?


I have a UITableView with about 400 cells in 200 sections and it's a little sluggish in responding to user interaction (scrolling, selecting cells.) I've made sure the methods for retrieving cells and header views do the bare minimum as it's running, and I don't think I'm doing anything out of the ordinary to make it slow. The cells and headers just have a background image and text. Has anyone else had this kind of problem, and do you know any way to make it run a little faster?

Edit: I'm offering a bounty because I'd love to get some useful feedback on this. I don't think the answer lies in a problem in my code. Instead I'm looking for strategies to re-engineer the UITableView so that it runs faster. I'm totally open to adding new code and I look forward to hearing what you guys have to say.

Sluggishness is observed on both the simulator and my device, an iPhone 4. Here are my implementations of viewForHeaderInSection and cellForRowAtIndexPath, which are the only UITableViewDelegate methods implemented nontrivially. I am reusing cells and header views.

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger) section
{
    HaikuHeaderView* view= [m_sectionViews objectAtIndex:section];
    NSMutableArray* array= [m_haikuSearch objectAtIndex:section];
    Haiku* haiku= [array objectAtIndex:0];

    [view.poetLabel setText:[haiku nameForDisplay]];

    return view;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];

        cell.backgroundView= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell gradient2.png"]];

        // (Set up a bunch of label attributes in the cell...)
    }

    NSMutableArray* array= [m_haikuSearch objectAtIndex:indexPath.section];
    Haiku* haiku = [array objectAtIndex:indexPath.row];
    cell.textLabel.text = [haiku.m_lines objectAtIndex:0];

    return cell;
}

Solution

  • Even if your cell is actually that simple (background image and label) there are some things to consider

    Image caching This is the obvious thing - if you are using the same image everywhere, load it once into the UIImage and reuse it. Even if the system will cache it on its own, directly using the already loaded one should never hurt.

    Fast calculation Another rather obvious thing - make calculating height and content as fast as possible. Don't do synchronous fetches (network calls, disk reads etc.).

    Alpha channel in image What's expensive when drawing is transparency. As your cell background has nothing behind it, make sure that you save your image without alpha channel. This saves a lot of processing.

    Transparent label The same holds true for the label on top of your background view, unfortunately making it opaque might ruin the looks of your cell - but it depends on the image.

    Custom cell In general, subclassing UITableViewCell and implementing drawRect: yourself is faster than building the subview hierarchy. You might make your image a class variable that all instances use. In drawRect: you'd draw the image and the text on top of it.

    Check compositing The simulator has a tool to highlight the parts that are render-expensive because of transparency (green is ok, red is alpha-blending). It can be found in the debug menu: "Color Blended Layers"