I’m using Grand Central Dispatch to load images of a UITableViewCell asynchronously. This works well except in some border cases in which the cell is reused, and a previous block loads the wrong image.
My current code looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSString *imagePath = [self imagePathForIndexPath:indexPath];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
dispatch_sync(dispatch_get_main_queue(), ^{
cell.imageView.image = image;
[cell setNeedsLayout];
});
});
return cell;
}
As far as I know GCD queues cannot be stopped. How can this border case be prevented then? Or should I be using something else instead of GCD to solve this problem?
what i’ve done is added an
NSOperationivar to the cell. the operation is responsible for getting, loading, and creating the image. when completed, it pings the cell. when/if the cell is dequeued, the operation is cancelled and destroyed if it has not finished. the operation test for cancellation when in-main. after the image is passed to the cell, the cell drops the operation and uses the image.