Iphone 如何在iOS上取消ApplicationIdentinterBackground中的工作线程
我已经仔细研究了一个合适的解决方案,但没有成功: 我的iPhone应用程序根据用户需求通过NSURL请求更新数据。在线加载的每个文件的大小只有1.5k,但一次更新可以包含400个这样的文件。因此,我在一个单独的线程中进行下载,该线程是可取消的,在更新过程中,有一个UIAlertView,带有进程指示和取消按钮。该设备可能会运行1…3分钟,因此它可能会超过设备保持活动的超时时间,或者发生其他事情,我的应用程序将进入后台 当调用ApplicationIdentinterBackground时我什么也不做,我意识到我的应用程序被挂起,工作线程也被挂起。当应用程序再次出现在前台时,它会唤醒并继续工作。到现在为止,一直都还不错。当我再次出现在前台后按下cancel(取消)按钮时,我遇到了麻烦——然后线程会做出被取消的反应(正如它应该做的那样),但立即再次运行,并在最后崩溃(在Apple框架的深处有错误代码)。只要应用程序保持在前台,它就可以完美地取消线程,因此我的想法是在输入ApplicationIdentinterBackground时停止/取消线程。我已经尝试了一些方法,但是每次尝试都会导致工作线程在调用ApplicationIdentinterBackground时挂起,因此我无法取消线程并等待。我试过的一个例子是:Iphone 如何在iOS上取消ApplicationIdentinterBackground中的工作线程,iphone,multithreading,user-interface,Iphone,Multithreading,User Interface,我已经仔细研究了一个合适的解决方案,但没有成功: 我的iPhone应用程序根据用户需求通过NSURL请求更新数据。在线加载的每个文件的大小只有1.5k,但一次更新可以包含400个这样的文件。因此,我在一个单独的线程中进行下载,该线程是可取消的,在更新过程中,有一个UIAlertView,带有进程指示和取消按钮。该设备可能会运行1…3分钟,因此它可能会超过设备保持活动的超时时间,或者发生其他事情,我的应用程序将进入后台 当调用ApplicationIdentinterBackground时我什么也
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;
});
}
我对整个队列没有经验,在某处发现了这样的构造。我假设所有在主线程和工作线程中分派的工作都保持挂起状态,因此我没有任何机会取消它。有什么好主意吗
我也读过关于在没有多线程的情况下做任何事情的尝试,但我并不十分欣赏。是否有一些有用的链接可以正确处理“转到后台”的情况?您可以在后台线程中包装您的线程工作,如:
...
[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];
}
}
这样做的目的是继续执行正在进行的任务,当应用程序处于后台时,该任务将继续执行-我在我的线程密集型/网络密集型应用程序中有几个地方这样做
AFAIK:你不必等到应用程序被后台处理后才调用beginBackgroundTask——你应该在应用程序有需要完成的功能时调用它,而不会被中断/挂起
我还将NSURLRequest用于:
[request setNetworkServiceType:NSURLNetworkServiceTypeVoIP];
(并在supportedbackgroundmodes标志中使用voip后台模式)我认为GCD不是进行网络编程的最佳方式。尝试使用NSURLConnection委托接口等异步下载数据。这降低了应用程序的复杂性,避免了多线程编程的麻烦。我还没有使用NSURLConnection,其余的都已经完全实现了。如果没有别的路,我就走这条路。目前的情况是,由于演示数据暂时完全无效,我必须为整个更新过程阻止用户I/O。因此,我只允许GUI根据需要进行更新,并通过UIAlertView锁定用户交互。线程本身是用[[NSThread alloc]initWithTarget:selector:object:创建的,尽管后台挂起,但其所有处理工作正常。谢谢,确实如此。事实上,再次转换到前台时会发生一些奇怪的事情,但我想我可以解决它。