我使用NSOperationQueue
和NSOperation
的子类在我的应用程序中生成大量数据,因此计算量非常大。
当用户关闭应用时,调用processingQueue.cancelAllOperations()
。同样在我的NSOperation
子类中,我覆盖了cancel()
,让它将取消请求转发给执行实际繁重工作的类…
override func cancel() {
AppDelegate.instance.cancelDataGeneration()
super.cancel()
}
但这还不够。当我在数据生成过程中关闭应用程序时,它会在Xcode中崩溃。
我能做些什么来防止崩溃(可能导致数据丢失)?是否可以让应用程序等待关闭,直到所有并发操作被取消,这是如何做到的(如果它甚至是可能的)?或者通常使用什么其他方法来解决这个问题?
更新:
经过更多的调查,我发现NSOperation
子类上的cancel()
从未被调用,即使在applicationShouldTerminate
中调用processingQueue.cancelAllOperations()
之后。所以我添加了一个方法来手动调用cancel:
func cancelDataGeneration() {
if let op = AppDelegate.instance._operation {
op.cancel();
}
}
我从applicationShouldTerminate
内部调用它(因为applicationShouldTerminate
比applicationWillTerminate
更早被调用)。有趣的是,因为我的AppDelegate是一个Singleton,我必须使用AppDelegate.instance._operation
。如果我只检查_operation
,当从applicationShouldTerminate
调用时,结果是nil
。我很想知道为什么会这样。
在任何情况下,取消现在可以正常工作:当应用程序退出时,它将取消数据生成类并退出而不会崩溃…主要是无论如何。但我仍然想知道为什么我的NSOperation
子类' cancel()
不调用当我使用processingQueue.cancelAllOperations()
!
来自Apple的文档
取消操作不会自动将其从队列中删除或停止当前正在执行的操作。对于排队等待执行的操作,队列必须在确认该操作已被取消并将其移至完成状态之前仍尝试执行该操作。
我会阻塞应用程序的主线程,直到NSOperationQueue完成它所有的工作。
[NSOperationQueue cancelAllOperations]
。然后在"应用程序将终止"方法中,我将调用[NSOperationQueue waitUntilAllOperationsAreFinished]。这将确保当前正在执行的块(所有其他排队的任务将被取消)将在应用程序退出之前完成。
现在,如果你对主线程blocking
感到不舒服,直到当前执行的块完成,那么你需要检查一个标志(或者NSApplicationDelegate
可以设置在那个类上),它表明应用程序是否仍然是活动的,以便继续。如果要终止应用程序,则终止块voluntarily
的fall out
,这是最干净的方法。
大致如下:
void ^(aBlock)(void) = ^void(void)
{
for(NSUInteger i = 0;i < 1000; i++)
{
// heavy processing code. Taking several iterations each second
// At the start of each iteration, check for a flag, to see if to quit
if(_applicationIsShuttingDown) break;
// perform block operation
}
};
你的类是一个NSApplicationDelegate并实现
-applicationWillTerminate:(NSNotification *)aNotification
{
_applicationIsShuttingDown = YES;
}