Asynchronous Loading of Images in a UITableView

Date Arrow  March 8, 2009

This is one of the most common scenarios for network- + UITableView-based applications; a UITableView instance whose contents come from the network; not only the text, but also the images! Somehow we all want to reproduce the behavior of the App Store (or of the iTunes) iPhone application, where the icons (or covers) of the apps (or songs) are downloaded one by one, as you scroll the table, without crashing nor opening 1000 simultaneous network connections.

My solution (there might be many others!) consists in the following key elements:

  • Avoid loading images right after the RSS feed is parsed; instead, use the -tableView:willDisplayCell:forRowAtIndexPath: delegate method in the controller to trigger the loading of the image for cells that become visible; this ensures that only the cells that are visible will receive the order to load images from the network;
  • Use a “model” class for each element of the table, and make the custom UITableViewCell subclass a delegate of this model object; then, the model object is responsible of loading its own image, and will tell the UITableViewCell when done;
  • Use the ASIHTTPRequest framework, with a shared download queue in the application delegate, so that all of the requests are properly queued, and network resources are properly used;
  • Show feedback to the user with scrolling wheels whenever and wherever appropriate;
  • Use the Reachability class from Apple’s own sample code to see if we’re really connected to Flickr, and otherwise show an error to the user.

I have created a sample project, as usual in Github, where I gather RSS data from Flickr’s public feed, and then I download synchronously the preview images of the feed. I even included a very simple Core Animation effect which reminds me of how the iTunes iPhone application allows us to hear previews of the songs we want to buy (the image flips and shows another view “behind”).

Feel free to contribute, fork, enjoy, read, use in your own projects, as you want. As I said, there might be many other (and most probably better) approaches to do this, so feel free to leave your comments below, as usual.

Similar Posts:

Tagged   Code · Open Source · iPhone

18 Comments

  • #1.   Stephan Burlot
    03.08.2009

    Nice code, as usual!

    I would suggest an improvement: instead of using willDisplayCell to load new cells, use scrollViewDidEndDecelerating and scrollViewDidEndDragging, so you dont load cells if the user scrolls fast through all cells.

    See: http://idevkit.com/forums/tutorials-code-samples-sdk/2-dynamic-content-loading-uitableview.html

  • #2.   Adrian
    03.08.2009

    Excellent idea! I’ve just adapted the code in idevkit.com and pushed it to Github. Thanks!

  • #3.   Jai
    08.02.2009

    Thanks for the example, was just what I was looking for as in introduction into grabbing images asynchronously.

    Still trying to get my head wrapped around some aspects of the UI framework, and can’t quite work out how you set the default.png as I can’t find a reference to it in the source in XCode or in the Interface Builder….?

  • #4.   Adrian
    08.02.2009

    Hi Jai! Default.png (with capital “D”, afaik) works a bit as a “magical” image, and it’s loaded automatically by your app; no need to set up anything at all.

  • #5.   Sorin
    09.09.2009

    Hello Adrian,
    really useful code! Thank you i changed a part of my app and now it works faster :) i have a question though.. initially i want to show an logo image under de activity indicator(not only the activity indicator).. where should i put it? i tried to set the image when i set the cell but it doesn’t load. any suggestions?

    thank you

  • #6.   Kiran
    09.13.2009

    Thanks for the great sample! It is helping my app quite a bit.

    One issue I noticed: After the initial table populates with items, if you repeat the following steps, the app will crash:

    - tap one item in the main list
    - wait for the progress bar to start updating
    - tap back to get back to the RSS list before the progress bar has finished.
    - tap another thumbnail to start loading, wait for progress, tap back, etc.

    I’m guessing some cleanup code in FlickrItemController.m should fix this, but I just wanted to point it out in case anyone else had similar issues.

    Thanks again for the helpful sample.

  • #7.   Adrian
    09.13.2009

    Thanks Kiran for pointing this out! I’ll fix it as soon as I can.

  • #8.   Ankit Thakur
    10.20.2009

    Hi Adrian,
    Thanks for this app. I have used this app from github. But I am getting memory leaks on performance testing in iASIHTTPRequest framework classes.

    And I think the point which Kiran has referred for the crash may be pointing to this memory leak.
    And we are waiting for the updated framework without memory leaks. As these memory leaks are creating problem in the app when the results are huge in amount.

    Thanks again.

  • #9.   DenVog
    11.22.2009

    Hi Adrian. Thanks for sharing this. Any plans to make this v2.x compatible? I get a crash any time I select a row on a device running v2.2.1. Thanks.

  • #10.   Greg Maletic
    12.11.2009

    This part of your description is confusing to me:

    >Use a “model” class for each element of the table, and make the custom UITableViewCell subclass a delegate of this model object; then, the model object is responsible of loading its own image, and will tell the UITableViewCell when done;

    By the time the callback comes to the UITableViewCell, how do we even know if that cell is still being used to show the same data? (Perhaps it’s been re-purposed to show another row by this point…and if so, the image data being sent to the cell would be incorrect.) Perhaps we should check to see if the row is still displaying the same data? However, I don’t see any code in your sample that does this check.

    Am I misunderstanding, or this is a real concern?

    Thanks very much!

  • #11.   Gaurang
    12.21.2009

    I am getting objmsg error when I quickly push and pop the views

  • #12.   Kevin Smith iPhone Application | akosma software
    12.23.2009

    [...] notified by the nice guys from DenVog that the Kevin Smith iPhone application includes code from my Asynchronous UITableView sample, posted earlier this year. The app also features the MGTwitterEngine from Matt Gemmell, [...]

  • #13.   Marco
    02.01.2010

    Awesome! Thank you very much!
    I’m developing my very first app and this is just what I was looking for!
    Now I need to put the parsed RSS table in a TAB of my app … but I’m having some difficulties …
    Any hints? The big problem is appDelegate and downloadQueue
    Thanks!
    Marco

  • #14.   Joao Henrique
    02.24.2010

    Hey, first of all congratulation on your great code.
    In your app the parsed RSS view is your main view in your application.
    I want to use the same functionality but in a view that opens when the user presses a button inside a view that is in a tabbar. But I am having a lot of trouble with that. Any hints?

  • #15.   Adrian
    02.24.2010

    @Joao and @Marco sorry guys, but no idea, I can’t say where the problem is without looking at the code.

  • #16.   Joao Henrique
    03.05.2010

    Now i noticed that even in your app the detail view never loads the image when selected. Just shows the view with the loading bar empty.

    Why is that?

  • #17.   Tim
    03.06.2010

    Thanks for the useful code!
    Found a memory leak in FlickrCell with scrollingWheel, needs to be released in dealloc.

  • #18.   Joao Henrique
    03.07.2010

    FlickrItemController method viewDidAppear with bug…

    I don’t know why, but the property item.imageURL was giving error and the image was never being loaded. So I took the thumbnailURL and took the “_s” out, like this:

    NSString *imageUrlStr = item.thumbnailURL;
    imageUrlStr = [imageUrlStr stringByReplacingOccurrencesOfString:@"_s" withString:@""];

    NSURL *url = [NSURL URLWithString:imageUrlStr];

    Now it it working perfectly! Anyhow it is still a great code you’ve given us!

Commenting