Asynchronous Downloading of Images For Uitableview With Gcd

Asynchronous downloading of images for UITableView with GCD

The problem here is that your image-fetching blocks are holding references to the tableview cells. When the download completes, it sets the imageView.image property, even if you have recycled the cell to display a different row.

You'll need your download completion block to test whether the image is still relevant to the cell before setting the image.

It's also worth noting that you're not storing the images anywhere other than in the cell, so you'll be downloading them again each time you scroll a row onscreen. You probably want to cache them somewhere and look for locally cached images before starting a download.

Edit: here's a simple way to test, using the cell's tag property:

- (UITableViewCell *)tableView:(UITableView *)tableView 
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

cell.tag = indexPath.row;
NSDictionary *parsedData = self.loader.parsedData[indexPath.row];
if (parsedData)
{
cell.imageView.image = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^(void) {

NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:parsedData[@"imageLR"]];

UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.tag == indexPath.row) {
cell.imageView.image = image;
[cell setNeedsLayout];
}
});
}
});

cell.textLabel.text = parsedData[@"id"];
}
return cell;
}

Asynchronous UITableViewCell Image Loading Using GCD

You should call setNeedsLayout on the cell after setting the thumbnail.

From the Apple Doc:

"Call this method on your application’s main thread when you want to adjust the layout of a view’s subviews. This method makes a note of the request and returns immediately. Because this method does not force an immediate update, but instead waits for the next update cycle, you can use it to invalidate the layout of multiple views before any of those views are updated. This behavior allows you to consolidate all of your layout updates to one update cycle, which is usually better for performance."

GCD UITableView asynchronous load images, wrong cells are loaded until new image download

Rather than capturing the cell you need to capture the index path, then get the cell back using:

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

That way, if the cell is now off screen you'll get nil back and the image won't be set on the wrong cell.

The other thing you need to add after your dispatch_async() is a cell.imageView.image=somePlaceholderImage.

E.g.:

if (![[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingPathComponent:@"image.png"]])
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSString *url=[pat stringByAppendingPathComponent:@"comments.txt"];
NSString *u=[NSString stringWithContentsOfFile:url encoding:NSUTF8StringEncoding error:nil];
NSURL *imageURL=[NSURL URLWithString:u];
NSData *image=[NSData dataWithContentsOfURL:imageURL];
[image writeToFile:[pat stringByAppendingPathComponent:@"image.png"] atomically:YES];
dispatch_sync(dispatch_get_main_queue(), ^{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:@"image.png"]];
[cell setNeedsLayout];
NSLog(@"Download");
});
});
cell.imageView.image=[UIImage imageNamed:@"placeholder"];
}
else
{
NSLog(@"cache");
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:@"image.png"]];
}

Easy load images asynchronously in a UITableView using GCD

Use NSCache to hold your downloaded images instead of NSDictionary. This will manage itself in low memory situations and remove items that haven't been accessed for a while. In that situation, they will be loaded from the URL again if needed.



Related Topics



Leave a reply



Submit