First, do not perform queue operations while scrolling. Instead, load images only for visible lines in viewDidLoad
and when the user stops scrolling:
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { for (NSIndexPath *indexPath in [self.tableView indexPathsForVisibleRows]) { [self loadImageForCellAtPath:indexPath]; } }
If you still want to cancel the download for invisible cells, you can use NSBlockOperation
instead of GCD:
self.operationQueue = [[[NSOperationQueue alloc] init] autorelease]; [self.operationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount]; // ... -(void)loadImageForCellAtPath:(NSIndexPath *)indexPath { __block NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ if (![operation isCancelled]) { NSString *galleryTinyImageUrl = [[self.smapi getImageUrls:imageId imageKey:imageKey] objectForKey:@"TinyURL"]; NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:galleryTinyImageUrl]]; dispatch_async(dispatch_get_main_queue(), ^{ if (imageData != nil) { UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; cell.imageView.image = [UIImage imageWithData:imageData]; } }); } }]; NSValue *nonRetainedOperation = [NSValue valueWithNonretainedObjectValue:operation]; [self.operations addObject:nonRetainedOperation forKey:indexPath]; [self.operationQueue addOperation:operation]; }
Here operations
are NSMutableDictionary
. When you want to cancel the operation, you will receive it with the indexPath
cell, cancel it and remove it from the dictionary:
NSValue *operationHolder = [self.operations objectForKey:indexPath]; NSOperation *operation = [operationHolder nonretainedObjectValue]; [operation cancel];
source share