Jonah
Jonah

Reputation: 4800

Jittery scroll performance in UITableView after iOS 4 upgrade

I have some large images in a grouped UITableView. There's 1 row in each section which holds the image and there is associated header and footer text for each section about the image. I worked hard to get it to scroll smoothly is iPhone OS 3.x and finally succeeded. But... when I upgraded to iOS 4, that all changed. Now there is very jerky performance whenever a new cell is loaded. Here is my cellForRowAtIndexPath code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"CellIdentifier";

    UIImageView *photo;
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    ApplicationDelegate *appDelegate = (ApplicationDelegate *)[[UIApplication sharedApplication] delegate];

    NSString *fileName = [NSString stringWithFormat:@"%@",[[appDelegate.sectionsDelegateDict objectAtIndex:indexPath.section] objectForKey:@"MainTrackImage"]];
    UIImage *theImage = [UIImage imageNamed:[[appDelegate.sectionsDelegateDict objectAtIndex:indexPath.section] objectForKey:@"MainTrackImage"]];

    imageHeight = CGImageGetHeight(theImage.CGImage);
    imageWidth = CGImageGetWidth(theImage.CGImage);

    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        photo = [[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, (imageHeight*320)/imageWidth)] autorelease];
        photo.tag = PHOTO_TAG;
        [cell addSubview:photo];
    } else {
        photo = (UIImageView *) [cell viewWithTag:PHOTO_TAG];
        [photo setFrame:CGRectMake(0, 0, 320, (imageHeight*320)/imageWidth)];
    }

    photo.image = theImage;
    return cell;
}

Note: I've tried using the following code in place of the "imageNamed" method with no success:

UIImage *theImage = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@", bundlePath,fileName]];

I've even tried pre-caching the images but with no success. Any help would be greatly appreciated.

UPDATE: I've tried experimenting with using Grand Central Dispatch to load the images by creating an image queue and loading them asynchronously:

dispatch_async(_image_queue, ^{
photoImageView.image = [imageCacheNS objectForKey:imageString];});

The problem I'm getting is that the images load very slowly and when I scroll the table, the previously viewed images are shown for a few seconds until the new image is loaded.

UPDATE 2: I still have not been able to make this work. I'm now looking into using the drawRect method to draw the cell. I'm hoping this will improve scrolling performance. Apple's tableViewSuite sample code example #5 shows how to do this, but I'm having trouble finding out how to make this work for my project. Anyone have any experience using drawRect: to loading images into a tableview?

Thanks!

Upvotes: 2

Views: 2558

Answers (4)

Jonah
Jonah

Reputation: 4800

After a huge amount of work and several communications with Apple dev support, I finally got this working. I am now loading very large images in a tableview in the background and have very fast scrolling performance.

Basically, I followed parts of the code from WWDC 2010 sample code "CoreAnimationImageBrowser". It's designed for the iPad and is based around a custom scrollView instead of a tableView, but the ImageScrollView class is the one to use to load your images.

Then, the really weird thing I had to do to account for the fact that the cells can't be preloaded in a tableView was to add the images as subviews BEHIND the tableView. As the table is scrolled, the images are already loaded and are quick to load.

Sort of a weird hack, but the Apple Tech seemed to think it was fine.

Good luck to anyone trying to do this. It took quite a bit of time for me to get it figured out.

Upvotes: 0

Dad
Dad

Reputation: 6478

re your: "The problem I'm getting is that the images load very slowly and when I scroll the table, the previously viewed images are shown for a few seconds until the new image is loaded." Bet that's because the image cell is being re-used but in the case where it's not nil you don't set the image property to nil to clear the old one out. Just a guess since your code is obviously now different than what is posted above.

BTW - I haven't used blocks yet in part because they require iOS 4 (unless you use non-apple compilers, i.e., PLBlocks) and I've been writing apps to still support 3.x. Just in case you were only building against 4.x now and might not realize the code you were writing was going to be a no-go on iOS 3.x (e.g., iPad for time being). Clearly you can do conditional code depending on the os version at runtime and so on.

Upvotes: 1

Dad
Dad

Reputation: 6478

The LazyTableImages sample code from Apple might help. http://developer.apple.com/iphone/library/samplecode/LazyTableImages/Introduction/Intro.html

Shows you how to load the images without blocking the UI.

Upvotes: 1

Jeff Kelley
Jeff Kelley

Reputation: 19071

Try loading the image in another thread. This will help improve the responsiveness of your table view (and other UI elements). This is a place where blocks and libdispatch would be excellent additions to your code.

Upvotes: 1

Related Questions