NSoperationQueue
オブジェクトを1に設定することで、オブジェクトをシリアルFIFOキューとして使用することはできmaxConcurrentOperationCount
ますか?
ドキュメントの状態に注意してください...
同時操作の最大数が1に設定されているキューの場合、これはシリアルキューに相当します。ただし、操作オブジェクトのシリアル実行に依存しないでください。
これは、FIFOの実行が保証されていないことを意味しますか?
NSoperationQueue
オブジェクトを1に設定することで、オブジェクトをシリアルFIFOキューとして使用することはできmaxConcurrentOperationCount
ますか?
ドキュメントの状態に注意してください...
同時操作の最大数が1に設定されているキューの場合、これはシリアルキューに相当します。ただし、操作オブジェクトのシリアル実行に依存しないでください。
これは、FIFOの実行が保証されていないことを意味しますか?
ほとんどの場合、FIFOになります。ただし、NSOperations間に依存関係を設定して、早期に送信された操作が、依存関係が満たされるまで他の操作がキュー内でそれを通過できるようにすることができます。
この依存関係の管理が、FIFO性を保証できないことをドキュメントが示している理由です。ただし、依存関係を使用していない場合は、依存関係に依存しても問題ありません。
更新:NSOperationにもqueuePriority
プロパティがあり、FIFO以外の順序で操作を実行することもできます。保留中の依存関係がない最も優先度の高い操作が常に最初に実行されます。
NSOperationサブクラスもオーバーライド-isReady
する可能性があり、これによりキューに戻る可能性があります。
したがって、キューでの実行はシリアルであることが保証されます。このキューでは、一度に1つの操作しか実行されません。しかし、AppleはFIFOを保証することはできません。それはあなたが行った操作で何をしているかに依存します。
ドキュメントに記載されているように、キューはFIFOではありません。新しい操作がキューに追加された最後の操作に依存し、一度に1つの操作しか実行できないようにする場合は、厳密に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とは関係がなく、ジョブのスケジューリングに関連しています。
編集:以下のコメントに続いて、カウントのチェックも十分でない場合はキューを一時停止します。このフォームは問題ないと思います(テスト時に、これは競合状態を作成せず、クラッシュしません)。
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
}
注:を使用している場合は、isReadyを編集できないため、1NSInvocationOperation
に設定するとうまくいく可能性があります。maxConcurrentOperationCount
ただしmaxConcurrentOperationCount
、独自のサブクラスを作成することを計画している場合、=1は適切なソリューションではありません。NSOperation
NSOperationの派生物では、isReady
関数をオーバーライドしてnoを返すことができるため(正しく機能するためにサーバーからのデータを待機する必要がある操作を想像してください)、これらの場合isReady no
は、本当に準備ができるまで戻ります。キュー内に追加する必要がありdependencies
ますoperations
アップルのドキュメントから、これはシリアルキューに相当します。ただし、操作オブジェクトのシリアル実行に依存しないでください。操作の準備が変更されると、結果の実行順序が変更される可能性があります