3

我的主线程上有一个 NSOperationQueue,它运行一组我希望能够随时取消的 NSOperations(最大并发设置为 1)。当我按下一个按钮时,我告诉队列取消所有操作并等到完成。这应该挂起主线程,直到操作队列为空,但是它无限期地挂起我的主线程。

这是我用来阻止它的代码:

...
[myQueue cancelAllOperations];
[myQueue waitUntilAllOperationsAreFinished];
return YES; // This line never gets called

注意:我需要使用waitUntilAllOperationsAreFinished,因为进一步的流程要求队列为空。

奇怪的是,这只发生在设备上。在模拟器中运行时,它按预期工作。

我已经观察了断点,我可以跟踪当前正在运行的操作,直到它完成。它检测到 [self isCancelled],停止它正在做的事情,然后一直运行到main方法的末尾。我可以看到操作中没有任何内容导致它挂起,并且通过取消所有操作,其他操作都不应该开始,队列应该完成。我已经通过添加断点进行了检查,并且没有其他操作开始。

为什么会这样?

4

3 回答 3

8

在您的任何操作(或任何其他线程)中,您使用的是-performSelectorOnMainThread:withObject:waitUntilDone:? -waitUntilAllOperationsAreFinished将阻塞它调用的任何线程,直到所有操作完成。奇怪的是,如果您在应用程序终止时调用它,那么该线程将是主线程。如果主线程被阻塞,并且其中一个操作使用-performSelectorOnMainThread:withObject:waitUntilDone:,您的应用程序将冻结,因为该操作永远不会完成。

我以前也发生过这样的事情。不幸的是,这很难解决。

于 2009-12-16T02:46:27.747 回答
5

你永远不应该阻塞主线程。它为一件事处理所有 UI 更新,另一件事正如您所注意到的那样,您设法创建了一个死锁。

相反,请尝试创建如下方法:

- (void) notifyOnFinish
{
   [myQueue waitUntilAllOperationsAreFinished];
   [self performSelectorOnMainThread:(queueEmpty) withObject:nil waitUntilDone:NO];
}

然后你现在有你的代码,调用:

[myQueue cancelAllOperations];
[self performSelectorInBackground:@selector(notifyOnFinish) withObject:nil];

在 queueEmpty 方法中,您只需在队列清空时执行您想做的任何事情。

基本上,只需创建一个后台线程来阻塞而不是主线程。

于 2009-12-16T05:14:46.670 回答
0

也许waitUntilAllOperationsArefFinished是导致阻塞......也许所有操作都在调用之前取消并完成waitUntilAllOperationsArefFinished,然后队列挂起,等待已经完成的操作完成......?

我不知道这一点,但也许试着不要打电话waitUntilAllOperationsArefFinished

于 2009-12-15T23:47:13.963 回答