NSOperationQueue串行FIFO队列

是否可以通过将其maxConcurrentOperationCount设置为1来将NSoperationQueue对象用作串行FIFO队列?

我注意到文档状态…

对于最大并发操作数设置为1的队列,这相当于一个串行队列。 但是,不应该依赖于操作对象的串行执行。

这是否意味着FIFO执行不能得到保证?

在大多数情况下,它将是先进先出。 但是,您可以设置NSOperations之间的依赖关系,以便提前提交的操作可以让其他操作在队列中传递,直到其相关性得到满足。

这种依赖性pipe理是为什么文档指出FIFO不能得到保证。 如果你不使用依赖关系,那么你应该可以依靠它。

更新 :NSOperation也有一个queuePriority属性,这也可以导致操作以非FIFO顺序执行。 没有挂起依赖关系的最高优先级操作将始终首先执行。

一个NSOperation子类也可能覆盖-isReady ,这可能导致它回到队列中。

所以在你的队列上的执行保证是串行的 ,因为在这个队列中一次只能运行一个操作。 但是苹果不能保证FIFO; 这取决于你所做的操作。

文档中提到的队列不是FIFO。 如果确保任何新操作取决于队列中添加的最后一个操作,并且一次只能运行一个操作,则可以将其严格设置为FIFO。 奥马尔解决scheme是正确的,但更一般的,你可以做到以下几点:

 NSOperationQueue* queue = [[ NSOperationQueue alloc ] init]; queue.maxConcurrentOperationCount = 1; NSOperation* someOperation = [ NSBlockOperation blockOperationWithBlock:^(void) { NSLog(@"Done.");} ]; if ( queue.operations.count != 0 ) [ someOperation addDependency: queue.operations.lastObject ]; 

这是可行的,因为queue.operations是一个数组:不pipe你添加的是不重新sorting的(例如它不是一个NSSet)。 你也可以简单地将一个类别添加到你的NSOperationQueue中:

 @interface NSOperationQueue (FIFOQueue) - (void) addOperationAfterLast:(NSOperation *)op; @end @implementation NSOperationQueue (FIFOQueue) - (void) addOperationAfterLast:(NSOperation *)op { if ( self.maxConcurrentOperationCount != 1) self.maxConcurrentOperationCount = 1; NSOperation* lastOp = self.operations.lastObject; if ( lastOp != nil ) [ op addDependency: lastOp ]; [ self addOperation:op]; } @end 

并使用[queue addOperationAfterLast:myOperation]。 queuePriority与FIFO无关,它与作业调度有关。

编辑:在下面的注释之后,如果检查计数,暂停队列也是不够的。 我相信这种forms是好的(经过testing,这不会造成竞争条件,也不会崩溃)。

一些信息: https : //developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperationQueue_class/#//apple_ref/occ/instp/NSOperationQueue/suspended

使用nsInvocationopration创build一个简单的FIFO您将需要设置一个操作依赖于另一个使用addDependency:方法

 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSInvocationOperation *oper1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"1"]; NSInvocationOperation *oper2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"2"]; NSInvocationOperation *oper3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"3"]; [oper2 addDependency:oper1]; [oper3 addDependency:oper2]; //oper3 depends on oper2 wich depends on oper1 //order of execution will ber oper1->oper2->oper3 //Changing the oreder will not change the result [queue addOperation:oper2]; [queue addOperation:oper3]; [queue addOperation:oper1]; - (void) doSth:(NSString*)str { NSLog(str); //log will be 1 2 3 //When you remove the addDependency calls, the logging result that i got where //different between consecutive runs i got the following //NSLog(str); //log will be 2 1 3 //NSLog(str); //log will be 3 1 2 } 

注意 :如果使用NSInvocationOperation那么将maxConcurrentOperationCount设置为1很可能会对您造成诡计,因为isReady不会被您编辑

但是,如果您计划创build您自己的NSOperation的子类, NSOperation = 1将不是一个好的解决scheme

因为在NSOperation衍生物中,你可以重写isReady函数并返回no(想象一些操作,需要等待一些数据从服务器到正常工作)在这种情况下,你会返回isReady no直到你真的准备好在这些您将需要在队列中的operations之间添加dependencies关系

从苹果文档, 这相当于一个串行队列。 但是,不应该依赖于操作对象的串行执行。 操作就绪的变化可以改变结果执行顺序

Interesting Posts