我有一个非并发的 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
还有另一种方法 -main 在 FooDownloadOperation 调用,它执行 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 循环中添加日志记录,它会按预期开始工作。我可以添加一些日志记录,但我真的很想知道为什么这似乎可以解决问题。