UICollectionView - Downloading images and effective reloading of data, like Instagram
afnetworking, cocoa-touch, ios, objective-c, uicollectionview
Solution
The technique you want to implement is called lazy loading. Since you are using `AFNetworking` it will be easier to implement this in your case. Each of your collection view cell needs to have a `UIImageView` to display the image. Use the `UIImageView+AFNetworking.h` category and set the correct image URL by calling method
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// ....
[cell.imageView setImageWithURL:imageURL placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
// ...
return cell;
}
Placeholder is the image which will be displayed until required image is downloaded. This will simply do the required job for you.
Note: By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:`.
Also, for you reference, if you want to implement lazy loading of images yourself, follow this Apple sample code. This is for `UITableView` but same technique can be used for `UICollectionView` as well.
Hope that helps!
Problem
I noticed that apps like Intagram uses `UICollectionViews` to display the feed of photos. I also noticed that the cells for these photos is somehow placed on screen before the actual photos are downloaded completely. Then when a download completes, that photo is nicely displayed in the correct cell. I would like to copy that functionality, but I do not know how to go about it. I am currently downloading a large JSON object which I transform to an array of NSDictionaries. Each `NSDictionary` contains information about each photo, and among that information, an URL is presented. At this URL, I can find the corresponding image that I need to download and display in my `UICollectionViewCells` As for now, I iterate this list and initiate a download for each URL I see. When that download is complete, I reload the collectionview using `[self.collectionView reloadData]`. But, as you can imagine, if I have 30 cells that all wants an image, there is a lot of `reloadData` calls. I am using AFNetworking to handle the download, here is the method, which I call based on the URL I mentioned before: ``` -(void) downloadFeedImages:(NSString *) photoURL imageDescs:(NSDictionary*)imageDescs photoId:(NSString *)photoID{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *directory = [paths objectAtIndex:0]; NSString* foofile = [directory stringByAppendingPathComponent:photoID]; if([[NSFileManager defaultManager] fileExistsAtPath:foofile]){ // IF IMAGE IS CACHED [self.collectionView reloadData]; return; } NSLog(@"photoURL: %@", photoURL); NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:photoURL]]; AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request imageProcessingBlock:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { // Save Image NSLog(@"URL-RESPONSE:%@", image); NSString *myFile = [directory stringByAppendingPathComponent:photoID]; NSData *imageData = UIImagePNGRepresentation(image); [imageData writeToFile:myFile atomically: YES]; [self.collectionView reloadData]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { NSLog(@"ERROR: %@", [error localizedDescription]); }]; [[WebAPI sharedInstance] enqueueHTTPRequestOperation:operation]; } ``` So basically, I wonder how I can achieve the functionality that Instagram and similar applications has when it comes to displaying a feed with images. In addition, I would like to know a good way to initiate a download for each cell, and when that download is finished, update that cell, not redraw the entire view using [reloadData] Thanks