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