iOS: Downloading Images Asynchronously (And Making Your UITableView Scroll Fast) is HARD

When I was first starting out as an iOS developer, I ran into an issue that every iOS developer faces sooner rather than later: How to Download Images Asynchronously. After I figured it out (or so I thought), I of course blogged about it.

But although my solution worked at first glance, it has a lot of issues:

  • Since the images are loaded asynchronously and the table view cells are re-usable, there is a big chance that your image will be loaded in the wrong cell. There needs to be a way to check that when the image downloads, the cell is still referring to the correct indexPath.
  • My caching system is super primitive – it stores the image in memory in a dictionary of objects. Obviously, that is not scalable at all.
  • The code is overall horrible in terms of Massive View Controller, etc 😁

To do it right, you’ll need to make something that:

  • Downloads an image asynchronously from an image URL – you can easily use NSURLSession for that.
  • From @alexito4:  It tracks ongoing request in order to not try to fetch same image twice while being downloaded.
  • Stores downloaded images to disk as a file
  • Has a way to easily access and load the images on disk asynchronously – via a cache key
  • Has a way to figure out whether the image is saved to disk and retrieve the saved image vs downloading it again via the image URL.
  • Has a way to clear the cache
  • You need a way to abstract this logic so it doesn’t clutter the ViewController, etc
  • You still have to make sure that the right image ends up in the right cell

The point is that although asynchronous image downloading is something that we need all the time in iOS development, it is not easy to do. I’ve even tried to write my own code recently, and the images wouldn’t scroll fast. My caching system was not good enough at loading lots of files really fast while managing to download new files. After looking at some of the caching implementation from Kingfisher, I don’t feel as bad. This stuff is tricky if you’re new to it.

So honestly, my suggestion is to leave it to the generous open source contributors and use an image downloading library. Kingfisher is my new favorite. But SDWebImage has been around for a while. And of course then there’s AlamofireImage if you’re already using Alamofire. Oh, and Facebook has a whole website with incredible documentation dedicated to AsyncDisplayKit 😬😬😬. There are other libraries as well that I haven’t mentioned but that should do the job as well.

Take the extra time to focus instead on all the other user-essential features in your app!

Update: @valeriyvan recommends watching this WWDC12 video on pre-rendering.

Also, if you’re still focused on writing this on your own [this blog post]( looks promising…

Enjoy the article? Join over 20,000+ Swift developers and enthusiasts who get my weekly updates.

  • Great overview!

    In my experience SDWebImage is the best choice in terms of performance.

    • pmusolino

      I agree with you.

      • I agree with you,too.

        • khunshan

          I agree with the agreers.

          • Utsav Dusad

            I don’t agree with this because SDWebImage still uses NSURLConnection instead of NSURLSession. It has been 3+ years since NSURLSession been there but they haven’t been able to make the changes.

  • IanKay

    I wrote a thing too that helps abstract _any_ asynchronous tasks out of cells

  • Dan

    Has somebody compared SDWebImage vs AlmofireImage? Because from what I read the old AFNetworking (image download part) was slower than the SDWebImage, but given the fact that AlamofireImage is a new implementation, maybe it changed in terms of performance?

    • Douglas Hewitt

      wondering the same thing

      • chandramani patel

        for my case SDWebImage is much faster than AlmofireImage .i hadbeen using alamofire/AFnetworking for past 3 years. I tested both in my current project and have seen SDWebImage responses are faster than alamofire.

  • Bogdan Geleta

    “My caching system is super primitive – it stores the image in memory in a dictionary of objects. Obviously, that is not scalable at all.”

    I advise to use NSCache over NSDictionary if dictionary is NSDictionary 🙂

  • Baibhav Singh

    for Xcode 7.2 ??

  • kean

    You may want to try Nuke 4. It goes further then others in terms of performance. One the recent features is rate limiting of the requests to support large collection views. Check it out!

    • Frederik Winkelsdorf

      I can only second this. Alexander does a very great job on his libraries, with clean and well structured code. Really worth giving them a try!