I've a uitableview which shows images in each cell, which are downloaded online.
To make this call async, I use NSBlockoperation. I prefer to use this, because i used GCD before but you cannot cancel GCD. The reason is that if I leave the view, the images gets downloaded at the background of the App, and when I get into the previous view again GCD would let it queue all again, so eventually there would be a whole stack of images and the user would never see the uitableview. So thats why I choose for NSBlockoperation.
However, my blocks don't get cancelled. This is the code I use (it is a part of - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { ):
// Create an operation without any work to do
downloadImageOperation = [NSBlockOperation new];
// Make a weak reference to the operation. This is used to check if the operation
// has been cancelled from within the block
__weak NSBlockOperation* operation = downloadImageOperation;
// Give the operation some work to do
[downloadImageOperation addExecutionBlock: ^() {
// Download the image
NSData *data = [NSData dataWithContentsOfURL:[newsimages objectAtIndex:indexPath.row]];;
UIImage *image = [[UIImage alloc] initWithData:data];
NSLog(@"%@",image);
// Make sure the operation was not cancelled whilst the download was in progress
if (operation.isCancelled) {
return;
NSLog(@"gestopt");
}
if (image != nil) {
NSData* imageData = UIImagePNGRepresentation(image);
[fileManager createFileAtPath:path contents:imageData attributes:nil];
cell.imageView.image = image;
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = 15.0;
}
// Do something with the image
}];
// Schedule the download by adding the download operation to the queue
[queuee addOperation:downloadImageOperation];
I've used this code to cancel:
-(void)viewDidDisappear:(BOOL)animated {
[downloadImageOperation cancel];
}
However, my NSLog tells me that even after my view dissappeared (i put an nslog there), there are still blocks.
2012-09-12 21:32:31.869 App[1631:1a07] <UIImage: 0x3965b0>
2012-09-12 21:32:32.508 App[1631:1907] <UIImage: 0x180d40>
2012-09-12 21:32:32.620 App[1631:707] view dissappear!
2012-09-12 21:32:33.089 App[1631:3a03] <UIImage: 0x3a4380>
2012-09-12 21:32:33.329 App[1631:5a03] <UIImage: 0x198720>
Notice: there are each time 4 cells displayed in the view, so I think that even though I leave the view they are still in the queue..
It appears that your code never has more than one block queued up - is this correct? If not then you need to send 'cancel' to the queue not to the operation.
Anyway, your problem is most likely this line:
That download is being done for you synchronously - so if you send 'cancel' just after this message then the cancel won't be seen for a long time. This is why most developers use concurrent NSOperations using asynchronous NSURLConnections to do the downloading - so the get the cancel message in real time.
Assuming this is ARC, you can add a log in a dealloc to verify that in fact the operation has finished or been cancelled, and was properly released. [note your log above is after the return so will never get called. you should also sprinkly more isCancelled messages around so you stop as soon as you can after getting cancelled.]