たとえば、次のように、「本物の」非同期メソッドをシリアル化できるようにしたかったのです。
- Web リクエストの作成
- UIAlertView を表示する
これは通常、扱いにくいビジネスであり、シリアル キューのほとんどのサンプルは、NSBlockOperation のブロックで「スリープ」を示しています。コールバックが発生したときにのみ操作が完了するため、これは機能しません。
NSOperation をサブクラス化することでこれを実装してみました。実装の最も興味深い部分は次のとおりです。
+ (MYOperation *)operationWithBlock:(CompleteBlock)block
{
MYOperation *operation = [[MYOperation alloc] init];
operation.block = block;
return operation;
}
- (void)start
{
[self willChangeValueForKey:@"isExecuting"];
self.executing = YES;
[self didChangeValueForKey:@"isExecuting"];
if (self.block) {
self.block(self);
}
}
- (void)finish
{
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
self.executing = NO;
self.finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
- (BOOL)isFinished
{
return self.finished;
}
- (BOOL) isExecuting
{
return self.executing;
}
これはうまく機能します。ここにデモンストレーションがあります...
NSOperationQueue *q = [[NSOperationQueue alloc] init];
q.maxConcurrentOperationCount = 1;
dispatch_queue_t queue = dispatch_queue_create("1", NULL);
dispatch_queue_t queue2 = dispatch_queue_create("2", NULL);
MYOperation *op = [MYOperation operationWithBlock:^(MYOperation *o) {
NSLog(@"1...");
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"1");
[o finish]; // this signals we're done
});
}];
MYOperation *op2 = [MYOperation operationWithBlock:^(MYOperation *o) {
NSLog(@"2...");
dispatch_async(queue2, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"2");
[o finish]; // this signals we're done
});
}];
[q addOperations:@[op, op2] waitUntilFinished:YES];
[NSThread sleepForTimeInterval:5];
スリープも使用しましたが、ネットワーク呼び出しをシミュレートするために、これらがバックグラウンド スレッドで実行されていることを確認しました。ログは次のようになります
1...
1
2...
2
これは希望どおりです。このアプローチの何が問題なのですか? 知っておくべき注意事項はありますか?