本文介绍了保持NSOperationQueue直到上一个操作完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想执行一些操作,只有在完成上一个操作后才需要启动下一个操作。我正在添加的操作将向服务器发送异步调用并接收数据。我想在第一次调用服务器完成从服务器接收数据后才开始下一个操作。怎么做?

I want to perform few operations and need to start the next operation only upon completion of the previous one. The operation I'm adding will send async call to the server and receive data. I want to start the next operation only after the first call to the server finish receiving data from the server. How to do that?

{....
     PhotoDownloader *pd = [[PhotoDownloader alloc] init];
     [GetGlobalOperationQueue addOperation:pd];
}

在PhotoDownloader中我将分配所需的参数并调用一个处理全局函数所有请求

Inside the PhotoDownloader I will allocate the required parameters and call a Global function which handles all the request

[GlobalCommunicationUtil sendServerReq:reqObj withResponseHandler:self];

在sendServerReq方法中,我将构建URL请求并将其发送到服务器,此调用是sendAsynchronousRequest调用。 PhotoDownloader将具有CommunicationUtil的委托方法。

Inside the sendServerReq method I will construct the URL request and send it to the server and this call is a "sendAsynchronousRequest" call. The PhotoDownloader will have the CommunicationUtil's delegate methods.

推荐答案

此问题分为两部分:


  1. 你问:

  1. You asked:

为此,理论上你可以简单地建立一个串行队列(如果你想要的话,这很好)使所有操作等到前一个操作完成)。使用 NSOperationQueue ,只需将 maxConcurrentOperationCount 设置为 1

To do this, you could, theoretically, simply make a serial queue (which is fine if you want to make all operations wait until the prior one finishes). With an NSOperationQueue, you achieve that simply by setting maxConcurrentOperationCount to 1.

或者,更灵活一点,您可以在需要依赖关系的操作之间建立依赖关系,但另外还要享受并发性。例如,如果您想要根据第三个完成取得两个网络请求,您可以执行以下操作:

Or, a little more flexible, you could establish dependencies between operations where dependencies are needed, but otherwise enjoy concurrency. For example, if you wanted to make two network requests dependent upon the completion of a third, you could do something like:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 4;   // generally with network requests, you don't want to exceed 4 or 5 concurrent operations;
                                         // it doesn't matter too much here, since there are only 3 operations, but don't
                                         // try to run more than 4 or 5 network requests at the same time

NSOperation *operation1 = [[NetworkOperation alloc] initWithRequest:request1 completionHandler:^(NSData *data, NSError *error) {
    [self doSomethingWithData:data fromRequest:request1 error:error];
}];

NSOperation *operation2 = [[NetworkOperation alloc] initWithRequest:request2 completionHandler:^(NSData *data, NSError *error) {
    [self doSomethingWithData:data fromRequest:request2 error:error];
}];

NSOperation *operation3 = [[NetworkOperation alloc] initWithRequest:request3 completionHandler:^(NSData *data, NSError *error) {
    [self doSomethingWithData:data fromRequest:request3 error:error];
}];

[operation2 addDependency:operation1];   // don't start operation2 or 3 until operation1 is done
[operation3 addDependency:operation1];

[queue addOperation:operation1];         // now add all three to the queue
[queue addOperation:operation2];
[queue addOperation:operation3];


  • 您问:

  • You asked:

    同样,这里有不同的方法。有时您可以使用信号量来使异步进程同步。但是,更好的是使用并发的 NSOperation 子类。

    Again, there are different approaches here. Sometimes you can avail yourself with semaphores to make asynchronous process synchronous. But, much better is to use a concurrent NSOperation subclass.

    异步 NSOperation 只是在发出 isFinished 通知之前无法完成的(从而允许它启动的任何异步任务完成)。并且 NSOperation 类仅通过在其 isAsynchronous YES 将其自身指定为异步操作/ code>实施。因此,异步操作的抽象类实现可能如下所示:

    An "asynchronous" NSOperation is simply one that will not complete until it issues a isFinished notification (thereby allowing any asynchronous tasks it initiates to finish). And an NSOperation class specifies itself as an asynchronous operation simply by returning YES in its isAsynchronous implementation. Thus, an abstract class implementation of an asynchronous operation might look like:

    //  AsynchronousOperation.h
    
    @import Foundation;
    
    @interface AsynchronousOperation : NSOperation
    
    /**
     Complete the asynchronous operation.
    
     If you create an asynchronous operation, you _must_ call this for all paths of execution
     or else the operation will not terminate (and dependent operations and/or available
     concurrent threads for the operation queue (`maxConcurrentOperationCount`) will be blocked.
     */
    - (void)completeOperation;
    
    @end
    

    //
    //  AsynchronousOperation.m
    //
    
    #import "AsynchronousOperation.h"
    
    @interface AsynchronousOperation ()
    
    @property (getter = isFinished, readwrite)  BOOL finished;
    @property (getter = isExecuting, readwrite) BOOL executing;
    
    @end
    
    @implementation AsynchronousOperation
    
    @synthesize finished  = _finished;
    @synthesize executing = _executing;
    
    - (instancetype)init {
        self = [super init];
        if (self) {
            _finished  = NO;
            _executing = NO;
        }
        return self;
    }
    
    - (void)start {
        if (self.isCancelled) {
            if (!self.isFinished) self.finished = YES;
            return;
        }
    
        self.executing = YES;
    
        [self main];
    }
    
    - (void)completeOperation {
        if (self.isExecuting) self.executing = NO;
        if (!self.isFinished) self.finished  = YES;
    }
    
    #pragma mark - NSOperation methods
    
    - (BOOL)isAsynchronous {
        return YES;
    }
    
    - (BOOL)isExecuting {
        @synchronized(self) { return _executing; }
    }
    
    - (BOOL)isFinished {
        @synchronized(self) { return _finished; }
    }
    
    - (void)setExecuting:(BOOL)executing {
        [self willChangeValueForKey:@"isExecuting"];
        @synchronized(self) { _executing = executing; }
        [self didChangeValueForKey:@"isExecuting"];
    }
    
    - (void)setFinished:(BOOL)finished {
        [self willChangeValueForKey:@"isFinished"];
        @synchronized(self) { _finished = finished; }
        [self didChangeValueForKey:@"isFinished"];
    }
    
    @end
    

    现在我们有了那个摘要,异步 NSOperation 子类,我们可以在具体的 NetworkOperation 类中使用它:

    Now that we have that abstract, asynchronous NSOperation subclass, we can use it in our concrete NetworkOperation class:

    #import "AsynchronousOperation.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    typedef void(^NetworkOperationCompletionBlock)(NSData * _Nullable data, NSError * _Nullable error);
    
    @interface NetworkOperation : AsynchronousOperation
    
    @property (nullable, nonatomic, copy) NetworkOperationCompletionBlock networkOperationCompletionBlock;
    @property (nonatomic, copy) NSURLRequest *request;
    
    - (instancetype)initWithRequest:(NSURLRequest *)request completionHandler:(NetworkOperationCompletionBlock)completionHandler;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    //  NetworkOperation.m
    
    #import "NetworkOperation.h"
    
    @interface NetworkOperation ()
    
    @property (nonatomic, weak) NSURLSessionTask *task;
    
    @end
    
    
    @implementation NetworkOperation
    
    - (instancetype)initWithRequest:(NSURLRequest *)request completionHandler:(NetworkOperationCompletionBlock)completionHandler {
        self = [self init];
    
        if (self) {
            self.request = request;
            self.networkOperationCompletionBlock = completionHandler;
        }
    
        return self;
    }
    
    - (void)main {
        NSURLSession *session = [NSURLSession sharedSession];
    
        NSURLSessionTask *task = [session dataTaskWithRequest:self.request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            if (self.networkOperationCompletionBlock) {
                self.networkOperationCompletionBlock(data, error);
                self.networkOperationCompletionBlock = nil;
            }
    
            [self completeOperation];
        }];
    
        [task resume];
    
        self.task = task;
    }
    
    - (void)cancel {
        [super cancel];
    
        [self.task cancel];
    }
    
    @end
    

    现在,在这个例子中,我正在使用这些异步网络请求的基于块的实现,但这个想法在基于委托的连接/会话中也同样有效。 (唯一的麻烦是 NSURLSession 指定其与任务相关的委托方法是会话的一部分,而不是网络任务。)

    Now, in this example, I'm using block-based implementation of these asynchronous network requests, but the idea works equally well in delegate-based connections/sessions, too. (The only hassle is that NSURLSession specifies its task-related delegate methods to be part of the session, not the network task.)

    显然,你自己的 NetworkOperation 类的实现可能会有很大不同(使用委托模式或完成块模式等),但希望这说明了并发操作。有关详细信息,请参阅章节,特别是标题为配置并发执行操作的部分。

    Clearly the implementation of your own NetworkOperation class may differ wildly (use delegate patterns or completion block patterns, etc.), but hopefully this illustrates the idea of a concurrent operation. For more information, see the Operation Queues chapter of the Concurrency Programming Guide, notably the section titled "Configuring Operations for Concurrent Execution".

    这篇关于保持NSOperationQueue直到上一个操作完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

  • 07-22 23:22
    查看更多