Many apps such as Tweetbot, Twitterrific, Alien Blue, etc. that display images from an API seem to load them in an asynchronous manner. It seems the initial viewable images are
There's no perfect answer. It's an art form to improve and tweak the various pieces involved to provide the best user experience for your app. Boiled down though, what you've described involves a proficient combination of the following:
Lazy loading
For lazy loading my absolute favorite goto is SDWebImage. To accomplish the effect you describe where the first 6 or 7 tweets don't load until the images are there you could hide the tweets initially and use SDWebImage's completion blocks to unhide them.
Pagination
Pagination refers to the practice of retrieving a set number of objects initially and pulling down the next X number of objects asynchronously before the user reaches them (usually initiated by a scroll). You could also extend this to to only load the images once the user's scroll slows or stops, so you don't waste time loading images the user scrolled right past. There are some great examples of this on GitHub, like NMPaginator, or you could roll your own using the UIScrollViewDelegate
methods.
Setup your scrollview delegate and implement:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate) {
[self loadImagesForVisibleRows];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self loadImagesForVisibleRows];
}
Then add a loadImagesForVisibleRows
method where you use [self.tableView indexPathsForVisibleRows];
to access the visible rows and lazy load the images for those rows.
Efficient payloads
Lastly, if you keep your payloads clean and light it'll save you some loading time, especially for users with weak network connections. I'd recommend Vinay's Sahni's blogpost, Best Practices for Designing a Pragmatic RESTful API, for a lot of great information on RESTful API design and pagination.
Welcoming any suggestions or additions to the above.
I've been using dispatch_async to load data asynchronously into my table view cells:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *imageData = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
[imageView setImage:image];
});
});
The images I used in this example were only a couple kilobytes large (each) and they loaded very well into the table view.
The Apple documentation has some sample code demonstrating ways to lazily load images into table view cells. It takes care of cancelling downloads for images that are scrolled out of sight and not starting image downloads at all until the user stops scrolling.
There are many solutions to this and you can find a lot of them here on stack overflow.
The basic idea is you want to load the image either in a block or an NSOperation
. I prefer an NSOperation
because you can cancel them which is useful when a cell scrolls off screen.
I recommend a controller to manage your image queue. Your table cell requests the image from the controller and if the controller has the image it returns it immediately. If it doesn't then it returns nil and fetches the image.
From here there are options. You could use a block to call back when the image is retrieved. I am not a fan of that but it is fairly popular. I prefer to use a NSNotification
when the image is received and the cell listens for the NSNotification
to populate.
I have a fairly complicated sample up on github that handles this as well as much much more. It is in my shared repository at http://github.com/ZarraStudios/ZDS_Shared. The main class is calledZSAssetManager
.
Note: This sample code is a few years old so it is not ARC
ready and will take some tweaking. It is also probably more complicated than you are looking for as it handles bandwidth detection and reaction as well. However it shows you what a production/high quality application does to handle asynchronous loading of images.
Enjoy.