Lagging on scroll UITableView when using network images
Wed 07 Oct 2015, 05:03
As a beginner, i realized that when i use network images, i can’t load images directly when UITableView load the data. It can make my tableview lagging and slower when i scroll it.
So i have to make my code load the images when user not scrolling the tableview. It happen too when I’m using UICollectionView. I found the solution from apple website: Lazy Table Image
it begins by loading the relevant text so the table can load as quickly as possible, then downloads the images for each row asynchronously when user stop scrolling so the user interface is more responsive and faster.
This is my code in .m file, I’m using json data, UIImageView, and UILabel in UITableViewCell:
- First, load the json data like what i do in this article Networking using NSURLSession.
- Then in @interface add this code:
// the set of IconDownloader objects for each app
@property (nonatomic, strong) NSMutableDictionary *imageDownloadsInProgress;
- add method for downloading the image:
- (void)startIconDownload:(DownloaderRecord *)downloaderRecord forIndexPath:(NSIndexPath *)indexPath
{
Downloader *downloader = (self.imageDownloadsInProgress)[indexPath];
if (downloader == nil)
{
downloader = [[Downloader alloc] init];
downloader.downloaderRecord = downloaderRecord;
[downloader setCompletionHandler:^{
UITableViewCell *cell = [self.tblView cellForRowAtIndexPath:indexPath];
UIImageView *imageView = (UIImageView*)[cell viewWithTag:2];
imageView.image = downloaderRecord.imageData;
// Remove the Downloader from the in progress list.
// This will result in it being deallocated.
[self.imageDownloadsInProgress removeObjectForKey:indexPath];
}];
(self.imageDownloadsInProgress)[indexPath] = downloader;
[downloader startDownloadImage];
}
}
- In tableView cellForRowAtIndexPath this is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
NSUInteger nodeCount = self.tblData.count;
if (nodeCount == 0 && indexPath.row == 0)
{
//this is will appear first when tableview loading the data or no data found.
cell = [tableView dequeueReusableCellWithIdentifier:@"loadingCell" forIndexPath:indexPath];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:@"menuCell" forIndexPath:indexPath];
if (nodeCount > 0)
{
DownloaderRecord *downloaderRecord = [[DownloaderRecord alloc] init];
downloaderRecord.url=[self.tblData valueForKey:@"articleImageUrl"][indexPath.row]; //load from NSDictionary
UILabel *labelCell = (UILabel *)[cell viewWithTag:1];
labelCell.text=[self.tblData valueForKey:@"articleTitle"][indexPath.row]; //load from NSDictionary
UIImageView *imageView = (UIImageView*)[cell viewWithTag:2];
if (!downloaderRecord.imageData)
{
if (self.tblView.dragging == NO && self.tblView.decelerating == NO)
{
[self startIconDownload:downloaderRecord forIndexPath:indexPath];
}
// if a download is deferred or in progress, return a placeholder image
imageView.image = [UIImage imageNamed:@"Placeholder.png"];
}
else
{
imageView.image = downloaderRecord.imageData;
}
}
}
return cell;
}
- Add this method to be used on scroll event:
// -------------------------------------------------------------------------------
// loadImagesForOnscreenRows
// This method is used in case the user scrolled into a set of cells that don't
// have their app icons yet.
// -------------------------------------------------------------------------------
- (void)loadImagesForOnscreenRows
{
if (self.tblData.count > 0)
{
NSArray *visiblePaths = [self.tblView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in visiblePaths)
{
DownloaderRecord *downloaderRecord = [[DownloaderRecord alloc] init];
downloaderRecord.url=[self.tblData valueForKey:@"articleImageUrl"][indexPath.row];
if (!downloaderRecord.imageData)
// Avoid the app icon download if the app already has an icon
{
[self startIconDownload:downloaderRecord forIndexPath:indexPath];
}
}
}
}
- this is the event when scrolling ended:
// -------------------------------------------------------------------------------
// scrollViewDidEndDragging:willDecelerate:
// Load images for all onscreen rows when scrolling is finished.
// -------------------------------------------------------------------------------
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate)
{
[self loadImagesForOnscreenRows];
}
}
// -------------------------------------------------------------------------------
// scrollViewDidEndDecelerating:scrollView
// When scrolling stops, proceed to load the app icons that are on screen.
// -------------------------------------------------------------------------------
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self loadImagesForOnscreenRows];
}
- Add this method for terminating all in progress download:
// -------------------------------------------------------------------------------
// terminateAllDownloads
// -------------------------------------------------------------------------------
- (void)terminateAllDownloads
{
// terminate all pending download connections
NSArray *allDownloads = [self.imageDownloadsInProgress allValues];
[allDownloads makeObjectsPerformSelector:@selector(cancelDownload)];
[self.imageDownloadsInProgress removeAllObjects];
}
- I use above method in dealloc and didReceiveMemoryWarning like what in sample code do:
// -------------------------------------------------------------------------------
// dealloc
// If this view controller is going away, we need to cancel all outstanding downloads.
// -------------------------------------------------------------------------------
- (void)dealloc
{
// terminate all pending download connections
[self terminateAllDownloads];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
// terminate all pending download connections
[self terminateAllDownloads];
}
That's it, hope it will help.
0
5206 views