我已经深入研究了一个合适的解决方案,但它没有发挥作用: 我的 iPhone 应用程序根据用户需求通过 NSURL 请求更新数据。在线加载的每个文件大小仅为 1.5k,但一次更新可以包含 400 个此类文件。因此,我在一个可取消的单独线程中执行下载内容,并且在更新期间有一个带有进程指示和取消按钮的 UIAlertView。该事情可能会运行 1...3 分钟,因此它可能会超过设备保持事件状态的超时时间或发生其他事情,并且我的应用程序将进入后台。
当我在调用 applicationDidEnterBackground 时什么都不做时,我意识到我的应用程序和工作线程都被挂起。当应用程序再次处于前台时,它会唤醒并继续工作。到目前为止,一切都很好。当我再次进入前台后按下取消按钮时,我遇到了麻烦 - 然后线程 react 为被取消(理应如此),但立即再次运行并在最后崩溃(在 Apple 框架深处的某个地方出现错误代码)。只要应用程序保持在前台,它就可以完美地取消线程 - 所以我的想法是在输入 applicationDidEnterBackground 时停止/取消它。我已经尝试了一些方法来做到这一点,但每次尝试都以工作线程在调用 applicationDidEnterBackground 时被挂起而告终,因此我无法取消线程并等待。我尝试过的一个例子是这样的:
diagView* viewDiagCtrl = startDiag.diagViewControl;
if (viewDiagCtrl != nil && viewDiagCtrl.actionThread != nil)
{
// UIBackgroundTaskIdentifier bgTask is instance variable
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler:
^{
dispatch_async(dispatch_get_main_queue(),
^{
NSLog(@"stopping actions definitely");
[viewDiagCtrl stopBackGroundActivity:self];
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(),
^{
// Start with 10ms time boxes
NSTimeInterval ti = 0.01;
while ([application backgroundTimeRemaining] > 1.0)
{
if (![viewDiagCtrl.actionThread isExecuting])
break;
NSDate* date = [NSDate dateWithTimeIntervalSinceNow:ti];
// Let the current run-loop do it's magif for one time-box.
[[NSRunLoop currentRunLoop] runMode: NSRunLoopCommonModes
beforeDate: date];
// Double the time box, for next try, max out at 1000ms.
ti = MIN(1.0, ti * 2);
}
[viewDiagCtrl stopBackGroundActivity:self];
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}
我对整个队列的内容没有经验,并且在某处找到了这样的构造。我假设所有在主线程中分派(dispatch)的工作都在工作线程中保持挂起状态,因此我没有任何机会取消它。有什么想法可以解决吗?
我还读过有关尝试在没有多线程的情况下完成所有操作的内容 - 但我不太欣赏这一点。是否有一些有用的链接可以正确处理“进入后台”情况?
最佳答案
您可以将线程工作包装在后台线程中,例如:
...
[self performSelectorInBackground:@selector(backgroundThread)
withObject:nil];
...
-(void)backgroundThread
{
// do a download once a minute in a background thread - dont let the system suspend us
while(true)
{
BOOL expire = NO;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{expire = YES;}];
while(!downloadComplete && !expire)
{
//do your multiple file downloads here;
}
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
[NSThread sleepForTimeInterval:60];
}
}
这将继续正在进行的任务,该任务将在应用程序后台运行时继续 - 我在我的重线程/网络密集型应用程序中的几个地方执行此操作。
据我所知:您不必等到应用程序进入后台才能调用 beginBackgroundTask - 只要您的应用程序有需要完成的功能而不被中断/挂起,您就应该调用它。
我还使用 NSURLRequest :
[request setNetworkServiceType:NSURLNetworkServiceTypeVoIP];
(并在supportedbackgroundmodes标志中使用voip后台模式)
关于iphone - 如何在 iOS 上取消 applicationDidEnterBackground 中的工作线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5355479/