iPhone – Downloading an image asynchronously. Revisited!

In a previous post I wrote about downloading an image asynchronously. As my work has progressed with my app (which is soon to be released on app store) I realized that the InternetImage class worked very well in the simulator but crashed my application very often on the actual device. The problem with the first version of the class was that it ran by itself, downloading the image and then calling back to it’s delegate when done. The delegate receiver was supposed to release the InternetImage class when it got the message. At first I was very content with the solution and found it pretty neat. However, when images are not downloaded as fast as they are on the simulator with a 24mbit internet connection, there’s a pretty big chance that the user didn’t wait for the image to load before moving to the next view in the application. What happens is:

  • An UIView allocs an InternetImage and tells it to start download an image with itself as the delegate receiver.
  • The user navigates to the next UIView which deallocs the current UIView.
  • A while later the image is downloaded and the InternetImage wants to use it’s delegate to inform the UIView that the image that it’s ready. However, the UIView doesn’t exits and the delegate could now point to whatever.
  • The application crashes with “BAD_ACCESS”. Or, the address of the delegate is now pointing to a different object that has been allocated at the same memory address which doesn’t crash the application but we have a memory leak as the InternetImage class doesn’t get dellocated.

This happens more often in a scroll view when you often want to load the next page in advance. On top of this major flaw in the design, it’s not very efficient to download an image that isn’t really needed anymore as the user has already navigate away from the view where it was to be shown.

So now I bring you a much better InternetImage class which is thoroughly tested not only on the simulator but also on a the actual device, my beautiful iPhone 3G :) .

This is what has been done to fix the flaws:

  • When using an InternetImage, make it a member of your class/view by retaining it.
  • To prevent the unnecessary download of an image that is no longer needed I’ve added an abort method.
  • When deallocating your view/class, always call abort on the InternetImage, then release it.

Other than that the InternetImage class remains the same. I’ve attached the new InternetImage class in a simple sample project. Happy coding!

Download: InternetImage sample

17 thoughts on “iPhone – Downloading an image asynchronously. Revisited!

  1. Great post; very informative. I’m wondering if you have any intentions of open sourcing InternetImage. Right now the files all say that they are “all rights reserved”, which means that no one else can use them.

  2. It is open source. It’s unfortunate that I wrote that in all the files previously. Everything on my blog is free to use and modify in any way you seem fit. I havn’t updated all the “old” code samples with a free to use statement, but my intent is that the code posted on my blog is free to use and modify by anyone.

    If you appriciate and use the code I would like it if your link back from your site/blog.

    Best regards,
    Björn

  3. Nice piece of code! But I have to say there are 2 memory leaks.

    1. You allocate InternetImage without releasing previous one.
    2. Same as above but with imageConnection.

    I also did this with an other class and also there there’s some general memory leak. I contacted apple about it and they told me to test it on 3.0 latest béta but I don’t want to lose my 2.2.1 install. Maybe you could test your code (or the URLCache apple sampleCode)

    Thanks,

    Cedric

  4. Hello Cedric,

    1. In the demo app I allocate a single InternetImage, there is no previous instance to release.
    2. Same with ImageConnection.

    I suspect the memory leaks are in your own implementation.

  5. I installed the example application on my iPhone.
    It works most of the times, but sometimes the image is never loaded although I have a perfect connection.

    You can test this by setting the iPhone into airplane mode and then turn it of. Now immediately when you get connection to the network start the application. The image will never load…

  6. yes there is memory leak about InternetImage.
    i just put a UIbutton in view.
    i pasted your code buttons event:
    [self downloadImageFromInternet:@"http://www.google.se/intl/en_com/images/logo_plain.png"];
    there is no memory leak when you first tap the button.
    but when you tap again
    there are memory leaks:
    InternetImage
    UIImage

    i also changed your connection code:

    NSURL *url = [NSURL URLWithString:ImageUrl];
    NSURLRequest *imageRequest = [[NSURLRequest alloc] initWithURL: url];
    imageConnection = [[[NSURLConnection alloc] initWithRequest:imageRequest delegate:self] autorelease];

    how can i solve it? i want to refresh the UIImage when the user taps button…
    thanx…

  7. Old post to comment on but the leak occurs when the image reaches a retain count of zero and dealloc is called… before abortDownload or connectionDidFinishLoading: is called. This causes a general leak of downLoadedImage and m_requestData. Adding [self abortDownload]; to the dealloc method should fix this.

  8. Thanks for posting this. It has been really helpful.

    How could I adapt the code to pull a URL stored in my db instead of hard coding one in as per your example? I am building a news app that pulls data, including image URL, from an XML feed into core data and so want to update the URL used with the relevant cell in the db.

    Thanks.

  9. Hi,

    I want to download zip file from the web into iphone application and the size of zip file in 1 gb. I am not able to figure the right way to do this on web. Please do the needful.

    Thanks and Regards
    Pawan Gera

  10. Hi it was a great tutorial really helped me a lot.. Is there any way to use this code if I want to download multiple items at the same time? Please share if there is any idea.
    Thanks :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>