【问题标题】:NSBlockoperation is not getting cancelledNSBlockoperation 没有被取消
【发布时间】:2012-09-12 19:43:23
【问题描述】:

我有一个 uitableview 显示每个单元格中的图像,这些图像是在线下载的。

为了使这个调用异步,我使用 NSBlock 操作。我更喜欢用这个,因为我以前用过 GCD 但你不能取消 GCD。原因是如果我离开视图,图像会在应用程序的后台下载,当我再次进入前一个视图时,GCD 会让它再次排队,所以最终会有一整堆图像和用户永远不会看到 uitableview。所以这就是我选择 NSBlockoperation 的原因。

但是,我的块并没有被取消。这是我使用的代码(它是 - (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];

我已使用此代码取消:

-(void)viewDidDisappear:(BOOL)animated {
[downloadImageOperation cancel];
}

但是,我的 NSLog 告诉我,即使在我的视图消失后(我在那里放了一个 nslog),仍然有块。

 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>

注意:视图中每次显示 4 个单元格,所以我认为即使我离开视图,它们仍在队列中..

【问题讨论】:

    标签: objective-c ios asynchronous uitableview nsblockoperation


    【解决方案1】:

    您的代码似乎从来没有超过一个块排队 - 这是正确的吗?如果不是,那么您需要将“取消”发送到队列而不是操作。

    无论如何,你的问题很可能是这一行:

    NSData *data = [NSData dataWithContentsOfURL:[newsimages objectAtIndex:indexPath.row]];;
    

    该下载正在为您同步完成 - 因此,如果您在此消息之后发送“取消”,那么很长一段时间内都不会看到取消。这就是为什么大多数开发人员使用并发 NSOperations 使用异步 NSURLConnections 来进行下载 - 所以实时获取取消消息。

    假设这是 ARC,您可以在 dealloc 中添加日志,以验证操作实际上已完成或已取消,并且已正确释放。 [请注意,您上面的日志是在返回之后,因此永远不会被调用。您还应该在周围散布更多 isCancelled 消息,以便在被取消后尽快停止。]

    【讨论】:

    • 实际上,对于每个 uitableviewcell,都会进行一个 nsblock 操作并添加一个执行块。这段代码是由 stackoverflow 上的某个人在另一个问题主题中提供的,但我现在很困惑要使用什么。我之前尝试过 gcd,因为我看到了很多关于它的教程和示例,但事实证明你无法取消块,所以我不知道在哪里看知道并且我不熟悉 nsblockoperation(虽然我阅读了文档和示例)跨度>
    • 您可以“某种程度上”取消该块。你有一个'__block BOOL cancel' ivar。每个块在开始重要工作之前都会对其进行检查。当你想取消时,设置标志,然后等待块完成(如果你使用 dispatch_group 你可以这样做)。我一直在使用它——这些块在几毫秒内完成。实际上,它与您在并发 NSOperations 中使用的技术相同。如果你想看看如何正确地做到这一点,我在 github 上放了一个简单易用的项目,它使用并发操作和异步 NSURLConnections:github.com/dhoerl/NSOperation-WebFetches-MadeEasy
    • 我查看了您提供的链接,但找不到您所说的 __block BOOL cancel ivar。我还阅读了有关块的其他主题,您可以通过将 BOOL 设置为 NO 来取消它,因此不会将其他块放入队列中。我认为这就像我的代码 if (operation.isCancelled) { 对吗?但是如果它已经在队列中,并且用户离开了屏幕怎么办? (viewdiddissappear)如何清空队列(我知道我不能删除当前的..)
    • 该代码中没有 __block,因为它使用 NSOperations,但是异步获取不会像您的“dataWithContentsOfURL”那样阻塞。无法修复您的代码,因为该行会阻塞,直到文件下载或请求失败。
    猜你喜欢
    • 2011-12-28
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    相关资源
    最近更新 更多