NSOperationQueue的取消所有操作直到它完成操作才会被取消。

9
在我的视图中,我有一个图像视图,该图像视图的数据来自URL,图片大小在1-3 MB左右。 如果用户滑动,我想加载下一张图片。如果缓慢地滑动,一切都正常,但是当我快速滑动时,我希望取消先前的操作并以新的URL开始。
例如,如果用户滑动4次,如果第2和第3个图像的操作在中途,我想取消这些操作并开始下载第4个图像。
但现在,在第4个图像的位置上,我得到第2个图像和第3个图像,然后才出现第4个图像。
以下是我的示例代码:
- (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 


         }];

     }];
 }

谢谢。

请努力格式化您的代码,以便其他人可以阅读它。 - jtbandes
1
每次需要加载图像时,您是否都在重新创建“BackgroundOperation”(使用“BackgroundOperation = [[NSOperationQueue alloc] init];”)? - Khanh Nguyen
3个回答

7
NSOperationQueue 上调用 cancelAllOperations 将仅调用其操作上的 cancel。如果 NSOperation 没有覆盖 cancel,那么它永远不会被取消。
一旦开始执行,就没有取消 NSBlockOperation 的概念。该块只是执行,然后结束。
如果您想指定特殊的取消行为(例如取消图像下载),则需要子类化 NSOperation 并覆盖 cancel
AFNetworkingSDWebImage 中有许多此类示例。
要取消图像下载,您需要将 NSURLSesionDownloadTask 包装到一个 NSOperation 中,然后覆盖 cancel 以调用 NSURLSesionDownloadTask 上的 cancel

不需要子类化NSOperation才能取消操作,可以在执行的代码块内完成取消。 - Yariv Nissim
1
那将取消该块,但是一旦图片下载开始,使用dataWithContentsOfURL仅仅是无法停止它的。 - DBoyer
“cancel” 并不会在所有操作上实际调用,它只是将 “isCancelled” 设置为 YES。 - trapper

6

取消一个操作只是将其 isCancelled 标志设置为 true。

在操作开始运行之前(如果它是长时间运行的,则在运行过程中),您需要负责检查操作是否已被取消。

您可以在操作块中检查操作是否已取消,但我建议使用子类,而不是使用块。


1
我没有清楚地理解,似乎我们需要检查isCancelled。但是我不确定在我的代码中应该在哪里检查它。 - siva krishna
我会尝试使用这个链接,但是我没有使用ARC,那么__weak NSBlockOperation *weakOperation = loadImageOperation的替代方法是什么? - siva krishna
请将 __weak 替换为 __block。 - user4151918
1
你应该使用ARC。为什么不用呢? - Yariv Nissim
@PetahChristian 有没有办法暂停和恢复操作? - siva krishna
显示剩余6条评论

3
取消操作只会将其isCancelled属性更新为YES
要能够取消操作,您应该执行以下操作:
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..
];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接