Reputation: 581
I'm new to working with GCD and I'm struggling to understand if what I'm doing here is the correct way to do things.
When I configure a cell, I want to extract a URL from a managed object and then dispatch a block to GCD to pull down the thumbnail image that resides at the URL.
Once the image downloads I am dispatching another block within the first block that puts the downloaded thumbnail into the cell.
When the table appears on screen I expect to see an activity spinner in each cell's thumbnail, with the thumbnail subsequently replaces with an actual image once it's finished downloading.
What actually happens is that the cells appear within the TableView and I don't see the spinner. If I click on a cell however, the image appears suddenly. Likewise if I navigate away from that view and then display it again. Additionally when I scroll the TableView up and down, something very strange happens - the thumbnails seem to "repeat" and then redownload as I scroll.
I'm sorry if that's a little hard to explain, but I don't know how best to describe what I'm seeing.
I'd appreciate if anyone could take a look at the code and perhaps give some suggestions as to what might be going wrong:
if([managedObject isKindOfClass:[Photo class]])
{
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[cell.imageView addSubview:spinner];
[spinner startAnimating];
Photo *photo = (Photo *)managedObject;
NSString *URLString = photo.thumbnailURL;
dispatch_queue_t callerQueue = dispatch_get_current_queue();
dispatch_queue_t downloadQueue = dispatch_queue_create("Thumb downloader", NULL);
dispatch_async(downloadQueue, ^{
NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:URLString];
dispatch_async(callerQueue, ^{
UIImage *thumbImage = [UIImage imageWithData:imageData];
[spinner stopAnimating];
cell.imageView.image = thumbImage;
[cell.imageView setNeedsDisplay];
});
});
dispatch_release(downloadQueue);
}
return cell;
Upvotes: 4
Views: 1391
Reputation: 8357
You should not directly access a cell after background loading of data (in this case image). If it scrolls off screen before you load the data, it's invalid. You should set the mechanisms off on their data loading way, and when it returns invoke [tableView reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation]
.
Upvotes: 4
Reputation: 10065
[cell.imageView addSubview:spinner];
The above line doesn't smell like it would work. try [cell.contentView addSubview:spinner];
instead. you will likely have to change the spinner's frame.origin to get it in the right place.
the thumbnails seem to "repeat" and then redownload as I scroll.
Since your tableViewCells are getting reused, the image being downloaded doesn't match the cell of the original fetch request.
in your inner,inner block, you need to verify that the cell still corresponds to the the managedObject/photo/indexPath you think is does.
Misc:
[spinner stopAnimating]
you probably want a [spinner removeFromSuperview]
Upvotes: 1