9

In my view i have image view, the data for image view comes form Url, the images are around 1-3 MB . If the user Swipes then i want to load the next image, Every thing works fine if swiped slowly, But when i swiped Fastly I want to Cancel the previous operation and start with new url.

For Ex. if user swipes 4 times if the operations for 2nd and 3rd images is in the middle, i want to cancel those and start downloading 4 th image

But now In the place of 4th image I’m getting first 2nd image follows 3rd and then 4 th image appears.

Here is my sample code

- (void)handleSwipeLeft:(UISwipeGestureRecognizer *)aSwipeGestureRecognizer {


    [BackgroundOperation cancelAllOperations];  // To cancel previous one 


    [self performSelector:@selector(LoadImage) withObject:nil afterDelay:0.1];


}

-(void)LoadImage
{
    BackgroundOperation=[[NSOperationQueue alloc]init];  


    imgvww.image=[UIImage imageNamed:@"loader.png"]; // Place holder    till download finishes 


   [BackgroundOperation addOperationWithBlock:^
     {
         UIImage *img=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[[self.ItemDetails objectAtIndex:0] objectForKey:@"ImageUrl"]]]];  // Getting data from URL 

         [[NSOperationQueue mainQueue] addOperationWithBlock:^{


             imgvww.image=img;  //Adding to image view after completion 


         }];

     }];
 }

Thank you.

siva krishna
  • 1,149
  • 2
  • 15
  • 23
  • Please make an effort to format your code such that other people can read it. – jtbandes Aug 29 '15 at 05:19
  • 1
    Are you recreating `BackgroundOperation` everytime an image needs to be loaded (with `BackgroundOperation=[[NSOperationQueue alloc]init];`)? – Khanh Nguyen Aug 29 '15 at 06:39

3 Answers3

7

Calling cancelAllOperations on an NSOperationQueue will simply call cancel on each of its operations. If the NSOperation does not override cancel then its never going to get cancelled.

There is no concept of cancelling an NSBlockOperation once it has started. The block simply executes and thats that.

If you want to specify special cancel behaviour (like cancelling your image download) you need to subclass NSOperation and override cancel.

There are many examples of this in AFNetworking or SDWebImage

To cancel an image download you need to wrap up an NSURLSesionDownloadTask in an NSOperation and then override cancel to call cancel on the NSURLSesionDownloadTask

DBoyer
  • 3,062
  • 4
  • 22
  • 32
  • no need to subclass an NSOperation to be able to cancel, it's possible to do it within the performed block – Yariv Nissim Aug 29 '15 at 06:50
  • 1
    That will cancel the block yes but once the image download has started there is no stopping it by simply using dataWithContentsOfURL – DBoyer Aug 29 '15 at 06:55
  • `cancel` is not actually called on all the operations, it just sets `isCancelled` to YES – trapper Feb 15 '17 at 03:24
6

Canceling an operation merely sets its isCancelled Flag to true.

You're responsible for checking to see if your operation has been cancelled, before it starts to run (or while it is running, if it is a long-running operation).

You can check if your operation is cancelled within an operation block but I'd recommend subclassing, instead of using a block.

Community
  • 1
  • 1
  • 1
    I didn't understand clearly, It seems v have to check isCancelled.But Im confused where to check it in my code – siva krishna Aug 29 '15 at 05:50
  • Im not using Nsoperation, It seems isCancelled exist for nsoperation – siva krishna Aug 29 '15 at 06:01
  • `NSBlockOperation` is a subclass of `NSOperation`. It can be cancelled. Check the link again and see how it captures the (weak) blockOperation, so isCancelled can be checked within the block. If you're still not sure how to do this, [check this detailed article](http://nghiatran.me/advanced-issues-the-right-way-to-load-content-in-backgrounds-thread-with-tableview/) which also cancels block operations. –  Aug 29 '15 at 06:11
  • K i will try with this link, But Im not using ARC, So whts the alternative for __weak NSBlockOperation *weakOperation = loadImageOperation; – siva krishna Aug 29 '15 at 06:24
  • Replace __weak with __block. –  Aug 29 '15 at 06:31
  • 1
    you should be using ARC. why don't you? – Yariv Nissim Aug 29 '15 at 06:52
  • @ yar1vn V started the project without ARC when v r supporting lower versions. But v r working on it to support ARC – siva krishna Aug 29 '15 at 07:25
  • @PetahChristian Is there any way to pause and resume the operation? – siva krishna Aug 29 '15 at 07:27
  • @siva you can suspend the queue, but it will not pause any operations that have already started. If you need more sophisticated control over the download, you need to use a different approach, like what DBoyer suggested. –  Aug 29 '15 at 07:33
  • @PetahChristian I will go through that, Thanks for Info – siva krishna Aug 29 '15 at 07:51
  • @siva Don't forget to upvote other answers. You've gotten some good help from several people! –  Aug 29 '15 at 07:55
3

Canceling the operation will only update its isCancelled property to YES.
To be able to cancel the operation, you should do the following:

NSBlockOperation * op = [NSBlockOperation new];
__weak NSBlockOperation * weakOp = op; // Use a weak reference to avoid a retain cycle
[op addExecutionBlock:^{
    // Put this code between whenever you want to allow an operation to cancel
    // For example: Inside a loop, before a large calculation, before saving/updating data or UI, etc.
    if (weakOp.isCancelled) return;

    // Do something..
];
Yariv Nissim
  • 13,273
  • 1
  • 38
  • 44