2

我创建了一个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阻塞线程直到所有操作完成。这可以解释为什么我没有看到任何事情发生并且一切都突然发生。

4

2 回答 2

5

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

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

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

根据您的情况,阻塞线程可能是合理的。如果阻塞不合理,但您想继续使用 NSOperation,则需要创建“并发”,NSOperation请参阅并发编程指南:为并发执行配置操作

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

当您收到一切都已完成的信号时,您可以按照文档中的说明适当地设置isFinished和标志以完成您的 main .isExecutingNSOperation

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

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

于 2013-02-13T13:12:12.663 回答
1

此代码不需要位于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
}]];
于 2013-02-12T12:55:53.130 回答