Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

UITableView Scrolling is Choppy When Displaying Images From Web

I'm going through the blog reader tutorial series. I've successfully displayed JSON data in my tableview cells, however, while testing the app on my phone I noticed the scrolling feels "choppy". However, if I just set the table cell image using imageNamed: and load the image from the documents directory, the scrolling is smooth. Why is this? How do I avoid choppy scrolling if I need to populate table cells with images from the web?

Thanks!

11 Answers

Amit Bijlani
STAFF
Amit Bijlani
Treehouse Guest Teacher

Adam Soffer I have created a video explaining how you can asynchronously load data and images using the Blog Reader app as an example. This will help you prevent choppy scrolling.

It uses NSURLSession and NSURLSessionDownloadTask

Thomas Nilsen
Thomas Nilsen
14,957 Points

Awesome video. Just one question. Personally when I used this for getting information from a JSON-file to display in a tableView, I used NSURLSessionDataTask. Why would you choose NSURLSessionDownloadTask instead? Both work obviously, but is there a particular advantage one has over the other?

Amit Bijlani
Amit Bijlani
Treehouse Guest Teacher

NSURLSessionDownloadTask downloads the data to disk whereas NSURLSessionDataTask keeps it in memory. If you are downloading large amounts of data then downloading data to disk makes sense, not mention NSURLSessionDownloadTask also supports cancel and resuming of a download.

Thank you very much for making this video!

Kyle V
Kyle V
781 Points

Thanks! This solved my question and made the scrolling much faster and responsive.

kennedy otis
kennedy otis
3,570 Points

The caching suggestion sounds really good.Would like to ask if we can see an example on how to cache the images and how to check from the cache before downloading them. Will really appreciate

Amit Bijlani
Amit Bijlani
Treehouse Guest Teacher

kennedy otis We will be launching the "Build a Photo Browser iPhone App" in a couple of weeks that will show you how to do all this in-depth.

Stone Preston
Stone Preston
42,016 Points

im guessing you are pulling images for each cell in cellForRowAtIndexPath? maybe try downloading all the images beforehand and saving them to an array, and using that array in cell for row instead of downloading them then.

Yup I was pulling the image for each cell in cellForRowAtIndexPath. Storing them in an array in viewDidLoad fixed the issue. Thanks Stone!

That won't really fix the issue, the fact that it was choppy tells me you're pulling them in on the main thread. You've just moved that problem to viewDidLoad: which could very well slow down the app earlier on. You should look into loading the images asynchronously.

Stone Preston
Stone Preston
42,016 Points

Aaron Daub makes a good point. You should get them asynchronously. This video from the ribbit app should explain it enough so you can apply it to your situation. It also conveniently deals with getting images.

Yup I was pulling the image for each cell in cellForRowAtIndexPath. Storing them in an array in viewDidLoad fixed the issue. Thanks Stone!

woops :p

kennedy otis
kennedy otis
3,570 Points

This was really helpful.Can this be used in production? Also I have a question concerning NSURLSessionDownloadTask, where you said it downloads to disk..is that data stored permanently there or only when using the the app?

Amit Bijlani
Amit Bijlani
Treehouse Guest Teacher

Yeah it is something you should be using in production.

From the Apple docs:

"An NSURLSessionDownloadTask object directly writes the response data to a temporary file. Upon completion, the session calls the delegate’s URLSession:downloadTask:didFinishDownloadingToURL: method. In that method, the app must either open the file for reading or move it to a permanent location in its sandbox container directory."

kennedy otis
kennedy otis
3,570 Points

Thanks that was really a nice lesson. Is it possible to get a lesson on how to create a spinner while waiting waiting for response instead of having a defaults value...

Rashii Henry
Rashii Henry
16,433 Points

if you're talking about a pull to refresh control, check out the build a self destructing iPhone App track. Its in one of the videos.

Stone Preston
Stone Preston
42,016 Points

you could use a UIActivityIndicatorView or a third party library like MBProgressHud

kennedy otis
kennedy otis
3,570 Points

MBProgessHud looks good. What I wanted is to know where can I be waiting for the response. same like ajax where you can have a spinner while waiting for data and on arrival you stop the spinner and display the data.

kennedy otis
kennedy otis
3,570 Points

I would like to make a music player with external songs which should be loaded from json. My intention is use TableView to display the list of songs and when user clicks a row, then the song at that row should play. I have managed to download the songs using NSURLSessionDownloadTask , which i am not sure if its the right way to do it,.. now issue is to proceed from there and play the songs. Below is my sample and the url contains the songs i would like to fill in my table.

{ status: "OK", tracks: [ { id: 1, name: "Tail Toddle", fileName: "tailtoddle_lo", url: "http://www.tonycuffe.com/mp3/tailtoddle_lo.mp3" }, { id: 2, name: "Sae Will We Yet", fileName: "saewill", url: "http://www.tonycuffe.com/mp3/saewill.mp3" }, ] }

Below is a snippet of how I am download the mp3 songs from the url

//Download the song from TrackURL

if([track.trackURL isKindOfClass:[NSString class]])
{

    NSURLSession *session = [NSURLSession sharedSession];

    NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[track getTrackURL] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {


        dispatch_async(dispatch_get_main_queue(), ^{


        });


    }];


    [task resume];
}

This is the furthest I have reached and am stuck on how to link the songs to the cell. Am using AVAudioPlayer of AVFoundation framework. I will really appreciate any help as am still newbie to ios and not much knowledge.

kennedy otis
kennedy otis
3,570 Points

Hi guys Would you advice on using the NSURLSession class if your json is only composed of data of type string only.. I mean no heavy files like images,video etc?

Quick question, in cellForRowAtIndexPath you are always creating a download task.... when cells are reused (if you scroll a few cells down) will the app always download the image over and over again? If so surely you should be storing the downloaded image in the sandbox documents folder and then checking if this exists before starting to download the image over and over again.

Amit Bijlani
Amit Bijlani
Treehouse Guest Teacher

Great question. The easiest way to avoid having to download the image all over again is to use a caching library like SAMCache. Once you download the image you cache it and the next time you check the cache first before you download it.

Thanks for the very fast answer!