1

非同時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ループ内にロギングを追加すると、期待どおりに機能し始めます。ロギングを追加することもできますが、なぜそれで問題が解決するのかを知りたいと思います。

4

1 に答える 1

0

いわばあなたのミキシングメタファー。NSOpeationが同時ではない場合、実行ループについて心配する必要はありません-実行中にメッセージを送信することはできません(その機能が必要な場合は、同時操作が必要であり、それらの使用方法に関するいくつかの例についてgithubを参照する必要があります)。

したがって、現在のスレッド(コード内の操作ではなく、メインアプリの現在のスレッド)を知る必要はありません。したがって、キューを作成し、一時停止し、一連の操作を追加します。実行し、キューを実行するように指示したい場合は、キューが完了するのを待つか、キューをポーリングするなどの方法があります。

于 2012-07-18T00:51:21.057 に答える