非同時NSOperationを実行しています。これには、多くのネットワーク呼び出しが行われ、結果が処理される部分があります。これは並列化の簡単なターゲットのように思えたので、次のようにしました。
NSOperationQueue *downloadOperationQueue = [[NSOperationQueue alloc] init];
downloadOperationQueue.maxConcurrentOperationCount = 5;
self.operationThread = [NSThread currentThread];
//prevent the operation queue from starting until we're ready to receive events
[downloadOperationQueue setSuspended:YES];
for (FooInfo *fooInfo in foos)
{
//FooDownloadOperation is a non-concurrent operation.
FooDownloadOperation *downloadOp = [[FooDownloadOperation alloc] initWithFoo:fooInfo];
downloadOp.delegate = self;
[downloadOperationQueue addOperation:downloadOp];
}
//unsuspend the queue and spin a run loop until the local operation count hits zero
[downloadOperationQueue setSuspended:NO];
while (self.isCancelled == NO && [downloadOperationQueue operationCount] > 0)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0f]];
}
// ... do other things
また、FooDownloadOperation呼び出しで-mainを実行する別のメソッドがあります。これは、performSelector:onThread:を実行してself.operationThreadに戻り、結果を処理します。
- (void)downloadOperation:(FooDownloadOperation *)downloadOp didSucceed:(NSArray *)results
{
if ([[NSThread currentThread] isEqual:self.operationThread] == NO)
{
//too many arguments for -performSelector:onThread:withObject:waitUntilDone:
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:_cmd]];
[inv setTarget:self];
[inv setSelector:_cmd];
[inv setArgument:&downloadOp atIndex:2];
[inv setArgument:&results atIndex:3];
[inv retainArguments];
[inv performSelector:@selector(invoke) onThread:self.operationThread withObject:nil waitUntilDone:YES];
return;
}
//... process the results
}
問題ない。理論的には。
実際、約70%の確率で、デバイスをスリープから復帰させて操作を実行した後、さらに悪いことに、デバイスはwhileループにとどまります。-runMode:untilDate:NOを返します。不思議なことに、20秒から6分後、ついにFooDownloadOperationsが開始されます。
さらに奇妙なことに、whileループ内にロギングを追加すると、期待どおりに機能し始めます。ロギングを追加することもできますが、なぜそれで問題が解決するのかを知りたいと思います。