主线程无限期挂起,等待NSOperationQueue操作取消[仅限设备!]

Mic*_*all 3 iphone multithreading nsoperation

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

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

...
[myQueue cancelAllOperations];
[myQueue waitUntilAllOperationsAreFinished];
return YES; // This line never gets called
Run Code Online (Sandbox Code Playgroud)

注意:我需要使用waitUntilAllOperationsAreFinished进一步的进程要求队列为空.

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

我看过断点,我可以按照当前运行的操作直到完成.它检测[self isCancelled],停止正在进行的操作并将其拉到main方法的末尾.我可以看到操作中没有任何东西导致它挂起,并且通过取消所有操作,其他任何操作都不应该启动,队列应该完成.我通过添加断点进行检查,其他操作都没有启动.

为什么会这样?

Bra*_*son 8

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

我之前发生过这件事.不幸的是,解决这个问题非常困难.


Ken*_*ner 5

你永远不应该阻止主线程.它可以处理所有UI更新,因为您已经注意到您设法创建了死锁.

相反,尝试创建一个方法,如:

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

然后,您现在拥有代码,请致电:

[myQueue cancelAllOperations];
[self performSelectorInBackground:@selector(notifyOnFinish) withObject:nil];
Run Code Online (Sandbox Code Playgroud)

在queueEmpty方法中,只需在清空队列时执行任何操作即可.

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