29056

UITableView On Screen Image Download Lazy Loading

First of all this is not a duplicate. I have seen some identical questions but they didn't help me as my problem varies a little bit.

Using the following code i am download the images asynchronously in my project.

{ NSURL *imageURL = [NSURL URLWithString:imageURLString]; [self downloadThumbnails:imageURL]; } - (void) downloadThumbnails:(NSURL *)finalUrl { dispatch_group_async(((RSSChannel *)self.parentParserDelegate).imageDownloadGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *tempData = [NSData dataWithContentsOfURL:finalUrl]; dispatch_async(dispatch_get_main_queue(), ^{ thumbnail = [UIImage imageWithData:tempData]; }); }); }

Due to the logic of the program, i have used the above code in files other than the tableview controller which is showing all the data after getting it from the web service.

<strong>PROBLEM:</strong> On screen images does not show up until i scroll. The off screen images are refreshed first. What can i do to solve my problem.

Apple's lazy loading project is using scrollViewDidEndDragging and scrollViewDidEndDecelerating to load the images but the project is way too big to understand plus my code is in files other than the tableview controller.

<strong>NOTE:</strong> Kindly do not recommend third party libraries like SDWebImage etc.

<strong>UPDATE:</strong> As most of people are unable to get the problem, i must clarify that this problem is not associated with downloading, caching and re-loading the images in tableview. So kindly do not recommend third party libraries. The problem is that images are only showing when the user scrolls the tableview instead of loading the on screen ones.

Thanks in advance

Answer1:

I think what you have to do is:

<ol> <li>

display some placeholder image in your table cell while the image is being downloaded (otherwise your table will look empty);

</li> <li>

when the downloaded image is there, send a refresh message to your table.

</li> </ol>

For 2, you have two approaches:

<ol> <li>

easy one: send reloadData to your table view (and check performance of your app);

</li> <li>

send your table view the message:

- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation </li> </ol>

Using reloadRowsAtIndexPaths is much better, but it will require you to keep track of which image is associated to which table row.

Keep in mind that if you use Core Data to store your images, then this workflow would be made much much easier by integrating NSFetchedResultController with your table view. See here for an example.

Again another approach would be using KVO:

<ol> <li>

declare this observe method in ItemsViewCell:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqual:@"thumbnail"]) { UIImage* newImage = [change objectForKey:NSKeyValueChangeNewKey]; if (newImage != (id)[NSNull null]) { self.thumbContainer.image = newImage; [self.thumbContainer setNeedsLayout]; } } } </li> <li>

then, when you configure the cell do:

RSSItem *item = [[channel items] objectAtIndex:[indexPath row]]; cell.titleLabel.text = [item title]; cell.thumbContainer.image = [item thumbnail]; [item addObserver:cell forKeyPath:@"thumbnail" options:NSKeyValueObservingOptionNew context:NULL]; </li> </ol>

By doing this, cell will be notified whenever the given item "thumbnail" keypath changes.

Another necessary change is doing the assignment like this:

self.thumbnail = [UIImage imageWithData:tempData];

(i.e., using self.).

ANOTHER EDIT:

I wanted to download and load the images just like in the LazyTableImages example by Apple. When its not decelerating and dragging, then only onscreen images are loaded, not all images are loaded at once.

I suspect we are talking different problems here.

I thought your issue here was that the downloaded images were not displayed correctly (if you do not scroll the table). This is what I understand from your question and my suggestion fixes that issue.

As to lazy loading, there is some kind of mismatch between what you are doing (downloading the whole feed and then archiving it as a whole) and what you would like (lazy loading). The two things do not match together, so you should rethink what you are doing.

Besides this, if you want lazy loading of images, you could follow these steps:

<ol> <li>

do not load the image in parser:foundCDATA:, just store the image URL;

</li> <li>

start downloading the image in tableView:cellForRowAtIndexPath: (if you know the URL, you can use dataWithContentOfURL as you are doing on a separate thread);

</li> <li>

the code I posted above will make the table update when the image is there;

</li> <li>

at first, do not worry about scrolling/dragging, just make 1-2-3 work;

</li> <li>

once it works, use the scrolling/dragging delegate to prevent the image from being downloaded (point 2) during scrolling/dragging; you can add a flag to your table view and make tableView:cellForRowAtIndexPath: download the image only if the flag says "no scrolling/dragging".

</li> </ol>

I hope this is enough for you to get to the end result. I will not write code for this, since it is pretty trivial.

PS: if you lazy load the images, your feed will be stored on disk without the images; you could as well remove the CGD group and CGD wait. as I said, there is not way out of this: you cannot do lazy loading and at the same time archive the images with the feed (unless each time you get a new image you archive the whole feed). you should find another way to cache the images.

Answer2:

Try using SDWebImage, it's great for using images from the web in UITableViews and handles most of the work for you.

Answer3:

The best idea is caching the image and use them. I have written the code for table view. Image on top of Cell It is a great solution.

Answer4:

Try downloading images using this code,

- (void) downloadThumbnails:(NSURL *)finalUrl { NSURLRequest* request = [NSURLRequest requestWithURL:finalUrl]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * response, NSData * data, NSError * error) { if (!error) { thumbnail = [UIImage imageWithData:data]; } }]; }

Recommend

  • Swift 2 Unable to remove optional binding
  • Block inside block = EXC_BAD_ACCESS
  • NSFetchedResultsController with NSPredicate not updating
  • Protecting critical code from being called again
  • How to force Composer to download a local package?
  • Yii2: Using Kartik Depdrop Widget?
  • How to Add Polymorphic Comments to Feed?
  • Xaml, wpf image position and crop issue
  • Getting different value with placeholder over CPU/GPU
  • nodemcu custom firmware build problems
  • Center align outputs in ipython notebook
  • Android changing fragment order inside FragmentPagerAdapter
  • Jquery popup on mouse over of calendar control
  • Access Android Market through SSH tunnel
  • How can I enlarge video fullscreen without the affected interface project in as3?
  • custom UITableViewCell with image for highlighting
  • How do I get HTML corresponding to current DOM tree?
  • Jackson Parser: ignore deserializing for type mismatch
  • How to use remove-erase idiom for removing empty vectors in a vector?
  • Python urlparse: small issue
  • How to create a file in java without a extension
  • FileReader+canvas image loading problem
  • Repeat a vertical line on every page in Report Builder / SSRS
  • Why is an OPTIONS request sent to the server?
  • Sending data from AppleScript to FileMaker records
  • vba code to select only visible cells in specific column except heading
  • ActionScript 2 vs ActionScript 3 performance
  • To display the title for the current loaction in map in iphone
  • Delete MySQLi record without showing the id in the URL
  • Unanticipated behavior
  • Traverse Array and Display in markup
  • Cannot Parse HTML Data Using Android / JSOUP
  • Comma separated Values
  • How to include full .NET prerequisite for Wix Burn installer
  • How to set the response of a form post action to a iframe source?
  • How get height of the a view with gone visibility and height defined as wrap_content in xml?
  • Trying to get generic when generic is not available
  • Getting Messege Twice Using IMvxMessenger
  • python draw pie shapes with colour filled
  • How to load view controller without button in storyboard?