保持NSOperationQueue,直到上一个操作完成

我只想执行一些操作,只有在完成前一个操作时才需要开始下一个操作。 我添加的操作将发送asynchronous调用到服务器并接收数据。 我只想在第一次调用服务器完成从服务器接收数据之后才开始下一个操作。 怎么做?

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

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

 [GlobalCommunicationUtil sendServerReq:reqObj withResponseHandler:self]; 

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

这个问题有两个部分:

  1. 你问:

    在上一个操作完成之前,如何让一个操作不能启动?

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

    或者,更灵活一些,您可以在需要依赖关系的操作之间build立依赖关系,但享受并发性。 例如,如果你想让两个networking请求取决于三分之一的完成,你可以做如下的事情:

     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]; 
  2. 你问:

    我如何确保在发出的asynchronousnetworking请求完成之前操作不会完成?

    再次,这里有不同的方法。 有时你可以利用信号来使asynchronous过程同步。 但是,更好的办法是使用并发的NSOperation子类。

    一个“asynchronous的” NSOperation只是一个在发出isFinished通知之前不会完成的任务(从而允许它启动的任何asynchronous任务完成)。 NSOperation类通过在isAsynchronous实现中返回YES来指定自己为asynchronous操作。 因此,asynchronous操作的抽象类实现可能如下所示:

     // 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 (atomic, readwrite, getter = isFinished) BOOL finished; @property (atomic, readwrite, getter = isExecuting) BOOL executing; @end @implementation AsynchronousOperation @synthesize finished = _finished; @synthesize executing = _executing; - (void)start { if (self.isCancelled) { self.finished = YES; return; } self.executing = YES; [self main]; } - (void)completeOperation { self.executing = NO; self.finished = YES; } #pragma mark - NSOperation properties - (BOOL)isAsynchronous { return YES; } + (NSSet *)keyPathsForValuesAffectingIsFinished { return [NSSet setWithObject:@"finished"]; } + (NSSet *)keyPathsForValuesAffectingIsExecuting { return [NSSet setWithObject:@"executing"]; } @end 

    现在我们有了这个抽象的,asynchronous的NSOperation子类,我们可以在我们具体的NetworkOperation类中使用它:

     #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 

    现在,在这个例子中,我使用基于块的方式来实现这些asynchronousnetworking请求,但是这个想法在基于委托的连接/会话中也同样适用。 (唯一的麻烦是NSURLSession其任务相关的委托方法指定为会话的一部分,而不是networking任务。)

    显然你自己的NetworkOperation类的实现可能会有很大的不同(使用委托模式或者完成块模式等等),但是希望这可以说明并发操作的思想。 有关更多信息,请参阅“ 并发编程指南 ”的“ 操作队列”一章,特别是标题为“configuration并发执行的操作”一节。

一个asynchronous操作的一个快速版本(这不是很明显):

 final class NetworkOperation: Operation { lazy var session: NSURLSession = { return NSURLSession.sharedSession() }() private var _finished = false { willSet { willChangeValue(forKey: "isFinished") } didSet { didChangeValue(forKey: "isFinished") } } private var _executing = false { willSet { willChangeValue(forKey: "isExecuting") } didSet { didChangeValue(forKey: "isExecuting") } } override var isAsynchronous: Bool { return true } override var isFinished: Bool { return _finished } override var isExecuting: Bool { return _executing } override func start() { _executing = true execute() } func execute() { task = session.downloadTaskWithURL(NSURL(string: "yourURL")!) { (url, response, error) in if error == nil { // Notify the response by means of a closure or what you prefer // Remember to run in the main thread since NSURLSession runs its // task on background by default } else { // Notify the failure by means of a closure or what you prefer // Remember to run in the main thread since NSURLSession runs its // task on background by default } // Remember to tell the operation queue that the execution has completed self.finish() } } func finish() { //Async task complete and hence the operation is complete _executing = false _finished = true } } 

要序列化操作:

 let operationQueue = OperationQueue() let operation1 = NetworkOperation() let operation2 = NetworkOperation() operation2.addDependency(operation1) operationQueue.addOperations([operation1, operation2], waitUntilFinished: false) 

使用NSOperationQueue是否适用?

这种行为很容易用串行队列来实现

https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

假设你有一个类来pipe理操作,你可以在你的init方法中创build一个串行调度队列

 queue = dispatch_queue_create("com.example.MyQueue", NULL); 

你会有一个方法来排队请求,像这样的东西

 - (void) enqueueRequest:(NSURL *)requestURL { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_sync(queue, ^{ /* get data from requestURL */ }) }); } 

这样,一次只有一个请求处于活动状态,即使每个请求都将在一个单独的后台线程中执行,并且多个请求将被排队,直到活动请求结束。