2 つの NSOperations を含む NSOperationQueue があり、1 に設定することでそれらを次々に実行するように設定されていますsetMaxConcurrentOperationCount
。
操作の 1 つは、Web から一部のデータを (もちろん別の操作スレッドで) 同期的に取得する標準の非同時操作 (単なるmain
メソッド) です。もう 1 つの操作は、非同期で実行する必要があるコードを使用する必要があるため、同時操作です。
問題は、同時操作が最初にキューに追加された場合にのみ機能することを発見したことです。非同時操作の後に来ると、奇妙なことにstart
メソッドは正常に呼び出されますが、そのメソッドが終了し、メソッドをコールバックするように接続をセットアップした後は、決して呼び出されません。その後、キュー内の操作は実行されません。start メソッドが返された後にハングアップし、URL 接続からのコールバックが呼び出されないかのようです。
並行操作が最初にキューに入れられた場合、すべて正常に機能し、非同期コールバックが機能し、完了後に後続の操作が実行されます。全然わからない!
以下の並行 NSOperation のテスト コードを見ることができます。
どんな助けでも大歓迎です!
メインスレッドの観察:
[start]
並行操作が最初にキューにある場合、メソッドがメインスレッドで呼び出されることを発見しました。ただし、キューの最初でない場合 (同時実行または非同時実行のいずれかの後)、[start]
メソッドはメイン スレッドで呼び出されません。これは、私の問題のパターンに適合するため、重要なようです。この理由は何でしょうか?
同時 NSOperation コード:
@interface ConcurrentOperation : NSOperation {
BOOL executing;
BOOL finished;
}
- (void)beginOperation;
- (void)completeOperation;
@end
@implementation ConcurrentOperation
- (void)beginOperation {
@try {
// Test async request
NSURLRequest *r = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.google.com"]];
NSURLConnection *c = [[NSURLConnection alloc] initWithRequest:r delegate:self];
[r release];
} @catch(NSException * e) {
// Do not rethrow exceptions.
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"Finished loading... %@", connection);
[self completeOperation];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"Finished with error... %@", error);
[self completeOperation];
}
- (void)dealloc {
[super dealloc];
}
- (id)init {
if (self = [super init]) {
// Set Flags
executing = NO;
finished = NO;
}
return self;
}
- (void)start {
// Main thread? This seems to be an important point
NSLog(@"%@ on main thread", ([NSThread isMainThread] ? @"Is" : @"Not"));
// Check for cancellation
if ([self isCancelled]) {
[self completeOperation];
return;
}
// Executing
[self willChangeValueForKey:@"isExecuting"];
executing = YES;
[self didChangeValueForKey:@"isExecuting"];
// Begin
[self beginOperation];
}
// Complete Operation and Mark as Finished
- (void)completeOperation {
BOOL oldExecuting = executing;
BOOL oldFinished = finished;
if (oldExecuting) [self willChangeValueForKey:@"isExecuting"];
if (!oldFinished) [self willChangeValueForKey:@"isFinished"];
executing = NO;
finished = YES;
if (oldExecuting) [self didChangeValueForKey:@"isExecuting"];
if (!oldFinished) [self didChangeValueForKey:@"isFinished"];
}
// Operation State
- (BOOL)isConcurrent { return YES; }
- (BOOL)isExecuting { return executing; }
- (BOOL)isFinished { return finished; }
@end
キューイング コード
// Setup Queue
myQueue = [[NSOperationQueue alloc] init];
[myQueue setMaxConcurrentOperationCount:1];
// Non Concurrent Op
NonConcurrentOperation *op1 = [[NonConcurrentOperation alloc] init];
[myQueue addOperation:op1];
[op1 release];
// Concurrent Op
ConcurrentOperation *op2 = [[ConcurrentOperation alloc] init];
[myQueue addOperation:op2];
[op2 release];