【问题标题】:NSOperationQueue INSIDE an NSOperationNSOperationQueue 在 NSOperation 内
【发布时间】:2013-02-12 12:48:46
【问题描述】:

我创建了一个NSOperation,其目标是从 20 个 URL 下载一些图像(如 20 个)。 所以在这个NSOperation 中我创建了20 个AFImageRequestOperation 将它们添加到NSOperationQueue 并在队列中调用-waitUntilAllOperationsAreFinished

问题是,它不会等待,它会立即返回。这是代码

- (void)main {
    NSArray *array = [I have the 20 links stored in this array];

    self.queue = [[NSOperationQueue alloc]init];
    self.queue.maxConcurrentOperationCount = 1;

    for (int i = 0; i < array.count; i++) {                
        NSURL *url = [NSURL URLWithString:[array objectAtIndex:i]];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        AFImageRequestOperation *op = [AFImageRequestOperation imageRequestOperationWithRequest:request imageProcessingBlock:^UIImage *(UIImage *image) {
            return image;
        } success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
        // SUCCESS BLOCK (not relevant)
        } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
        // FAILURE BLOCK (not relevant)
        }];

        [self.queue addOperation:op];
    }

    [self.queue waitUntilAllOperationsAreFinished]; // Here is the problem it doesn't wait
    DDLogWarn(@"-- %@ FINISHED --", self);

}

在控制台中,DDLogWarn(@"-- %@ FINISHED --", self); 在每个操作开始之前打印,所以我的猜测是waitUntilAllOperationsAreFinished 没有完成它的工作并且没有等待,但是 20 个操作仍在运行之后,这可能表示main 还没有返回,所以我不知道该怎么想了。

编辑1:实际上我想知道,如果我的DDLog 在成功和失败中阻塞,因为waitUntilAllOperationsAreFinished 正在阻塞线程,直到所有操作完成。这或许可以解释为什么我什么都没有发生,一切都突然发生。

【问题讨论】:

    标签: objective-c cocoa-touch afnetworking nsoperation nsoperationqueue


    【解决方案1】:

    出于与您类似的原因,我发现创建一个包含其他 NSOperationsNSOperation 很有用,即我有很多较小的任务组成了一个更大的任务,我想将更大的任务视为单个单元,并在完成时收到通知。我还需要序列化更大任务的运行,所以一次只运行一个,但是当每个大任务运行时,它可以在自身内部执行多个并发操作。

    在我看来,和你一样,创建NSOperation 来管理大型任务是一个不错的方法,而且我还没有阅读文档中说不要这样做的任何内容。

    看起来您的代码毕竟可以工作,因此您可以继续使用 NSOperation。

    根据您的情况,阻塞线程可能是合理的。如果阻塞不合理,但您想继续使用 NSOperation,则需要创建“并发”NSOperation 参见Concurrency Programming Guide: Configuring Operations for Concurrent Execution

    如果您一次只允许下载一个图像,您可以使用@jackslashs 建议来表示操作结束,或者如果您想允许同时下载图像,那么您可以使用单个NSBlockOperation 作为最终操作并使用-[NSOperation addDependency:] 使其依赖于所有其他操作,使其最后运行。

    当您收到一切都已完成的信号时,您可以按照文档中的说明适当地设置 isFinishedisExecuting 标志,以最终确定您的主要 NSOperation

    诚然,这有一定程度的复杂性,但您可能会发现它很有用,因为一旦将复杂性隐藏在 NSOperation 中,外面的代码可能会像我一样简单。

    如果您决定创建并发 NSOperation,您可能会发现 Apple 示例代码 LinkedImageFetcher : QRunLoopOperation 作为起点很有用。

    【讨论】:

    • 这正是我所需要的,为自己设置isFinishedisExecuting 标志。非常感谢你:)
    【解决方案2】:

    此代码不需要在NSOperation 中。而是创建一个类,也许是一个单例,它有一个操作队列并创建一个名为

    的方法
    -(void)getImagesFromArray:(NSArray *)array
    

    或类似的东西,您上面的代码将在该队列中正常工作。您无需致电waitUntilAllOperationsAreFinished。那是一个阻塞呼叫。如果您的队列的最大操作计数为 1,您可以在添加所有网络操作后添加另一个操作,然后当它执行时,您知道所有其他操作都已完成。您可以在末尾添加一个简单的块操作:

    //add all the network operations in a loop
    [self.operationQueue addOperation:[NSBlockOperation blockOperationWithBlock:^{
        //this is the last operation in the queue. Therefore all other network operations have finished
    }]];
    

    【讨论】:

    • 好吧,我应该多说一些,这 20 张图片就像一本书中的一章或专辑中的歌曲,或者我不知道,但我要加入很多这样的操作下载20个左右的项目,这就是为什么我想制作一个NSOperation
    • 也许我应该重新考虑整个事情,感谢您花时间回答。
    • AFImageRequestOperation 已经是 NSOperation。你不需要自己做!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    相关资源
    最近更新 更多