是否可以通过将NSoperationQueue
对象maxConcurrentOperationCount
设置为 1 来将其用作串行 FIFO 队列?
我注意到文档指出...
对于最大并发操作数设置为 1 的队列,这相当于串行队列。但是,切勿依赖操作对象的串行执行。
这是否意味着FIFO的执行无法保证?
在大多数情况下,它将是FIFO。 但是,您可以在 NSOperations 之间设置依赖关系,以便提前提交的操作将允许其他操作在队列中通过它,直到满足其依赖关系为止。
这种依赖关系管理是文档指出无法保证 FIFO 性的原因。但是,如果您不使用依赖项,则应该可以依赖它。
更新:NSOperation 还具有 queuePriority
属性,该属性还可能导致操作以非 FIFO 顺序执行。没有挂起依赖项的最高优先级操作将始终首先执行。
NSOperation子类也可能覆盖-isReady
,这可能导致它在队列中移回。
上的执行保证是串行的,因为在此队列中一次运行的操作不超过一个。但苹果不能保证FIFO;这取决于你对你投入的操作做了什么。
队列不是文档中提到的 FIFO。如果确保任何新操作都依赖于队列中添加的最后一个操作,并且一次只能运行一个操作,则可以将其严格设置为 FIFO。Omar 解决方案是正确的,但更一般地说,您可以执行以下操作:
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 是一个数组:您添加的任何内容都不会重新排序(例如,它不是 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 无关,它与作业调度有关。
编辑:在下面的评论之后,如果检查计数也不够,则暂停队列。 我相信这种形式很好(经过测试,这不会产生竞争条件,也不会崩溃)。
一些信息: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperationQueue_class/#//apple_ref/occ/instp/NSOperationQueue/suspended
使用 nsInvocationopration 创建一个简单的 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 将无法由您编辑
但是,如果您计划创建自己的NSOperation
子类,则 maxConcurrentOperationCount
= 1 将不是一个好的解决方案
由于在 NSOperation 衍生品中,您可以覆盖 isReady
函数并返回 no(想象一下某些操作需要等待来自服务器的一些数据才能正常运行),在这些情况下,您将返回isReady no
直到您真正准备好为止在这些情况下,您需要在队列内的operations
之间添加dependencies
从苹果文档中,这相当于一个串行队列。但是,切勿依赖操作对象的串行执行。操作就绪情况的更改可能会更改生成的执行顺序