iOS - 后台进程和 UI 更新
问题很简单:我的应用程序控制每次启动时是否有更新。如果有更新,将显示一个弹出窗口,并选择“是”或“否”。当用户点击“是”时,将启动 4 种方法。这些方法下载 xml 文件并上传 CoreData。这是警报的代码:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex==1) {
[self showActivityViewer];
[self downloadControlAndUpdatePoi];
[self downloadControlAndUpdateItinerari];
[self downloadControlAndUpdateArtisti];
[self downloadControlAndUpdateEventi];
[self hideActivityViewer];
NSLog(@"AGGIORNA");
} else {
NSLog(@"NON AGGIORNARE");
return;
}
}
但是有一个问题:当用户点击“是”时,警报不会消失并保留在屏幕上,直到所有方法完成。所以我尝试这个其他代码:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex==1) {
[self showActivityViewer];
[NSThread detachNewThreadSelector:@selector(startDownloads) toTarget:self withObject:nil];
[self hideActivityViewer];
NSLog(@"AGGIORNA");
} else {
NSLog(@"NON AGGIORNARE");
return;
}
}
-(void)startDownloads {
NSInvocationOperation *opPoi=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdatePoi) object:nil];
NSInvocationOperation *opItinerari=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateItinerari) object:nil];
NSInvocationOperation *opArtisti=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateArtisti) object:nil];
NSInvocationOperation *opEventi=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateEventi) object:nil];
NSArray *operations=[[NSArray alloc] initWithObjects:opPoi,opItinerari,opArtisti,opEventi, nil];
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
[queue addOperations:operations waitUntilFinished:YES];
[queue waitUntilAllOperationsAreFinished];
}
即使在这里也存在问题:我点击开始,但活动查看器没有出现。警报消失,线程启动并依次运行4个方法。
我需要在后台运行进程,就像我的第二个代码一样,但我什至需要运行我的 showActityViewer 方法并显示微调器。
谢谢 :)
the question is simple : my app control if there is an update every time it starts. If there is an update a popup will be shown with a Yes or No choose. When user tap Yes 4 methods start. These methods download xml file and upload CoreData. This is the code of the alert :
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex==1) {
[self showActivityViewer];
[self downloadControlAndUpdatePoi];
[self downloadControlAndUpdateItinerari];
[self downloadControlAndUpdateArtisti];
[self downloadControlAndUpdateEventi];
[self hideActivityViewer];
NSLog(@"AGGIORNA");
} else {
NSLog(@"NON AGGIORNARE");
return;
}
}
But there is a problem : when user tap Yes the alert doesn't disappear and remain on screen until all methods are finished. So i try this other code :
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex==1) {
[self showActivityViewer];
[NSThread detachNewThreadSelector:@selector(startDownloads) toTarget:self withObject:nil];
[self hideActivityViewer];
NSLog(@"AGGIORNA");
} else {
NSLog(@"NON AGGIORNARE");
return;
}
}
-(void)startDownloads {
NSInvocationOperation *opPoi=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdatePoi) object:nil];
NSInvocationOperation *opItinerari=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateItinerari) object:nil];
NSInvocationOperation *opArtisti=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateArtisti) object:nil];
NSInvocationOperation *opEventi=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateEventi) object:nil];
NSArray *operations=[[NSArray alloc] initWithObjects:opPoi,opItinerari,opArtisti,opEventi, nil];
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
[queue addOperations:operations waitUntilFinished:YES];
[queue waitUntilAllOperationsAreFinished];
}
There is a problem even here : i tap start, but the activity viewer doesn't appear. The alert disappear and the thread start and run the 4 methods one after another.
I need the processes run in background, just like happened with my 2nd code, but i need even my showActityViewer method will be run and show the spinner.
Thanks :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先要事。您不需要启动 4 个操作,因为您已经处于辅助线程中,并且不需要并行执行这 4 个操作。你可以简单地这样做:
最重要的是,如果你在
downloadControl*
方法中使用autorelease
,你需要在startDownloads
中定义一个自动释放池,否则我怀疑你将会有泄漏。至于为什么活动指示器不显示,这取决于您正在调用的事实:
在分离之后立即调用。因此,在 UI 有时间更新自身之前,您将显示并删除它。从那里删除该行并重写
startDownloads
如下:请注意,我正在调用主线程来
hideActivityViewer
因为只有主线程可以安全地使用UIKit< /代码>。
编辑:
我不知道您在下载方法中使用了 Core Data...
看看 与核心数据的并发。您将需要通过至少为辅助线程使用单独的托管对象上下文来稍微调整您的代码(我不知道您在那里创建 moc 是否可行)。
另请参阅此教程可可是我的女朋友。
作为所有这些的替代方案,您可以考虑这样做:
with:
这根本不使用线程,但我不确定活动查看器是否会显示没有任何故障。如果需要的话,可以进行更多级别的黑客攻击,并且您可以指定延迟
First things first. You don't need to start 4 operations, since you are already in a secondary thread and do not need that the 4 operations be executed in parallel. You could simply do:
Above all, you need define an autorelease pool in
startDownloads
if you useautorelease
in thedownloadControl*
methods, otherwise I suspect you will have leaks.As to why the activity indicator does not show up, it depends on the fact that you are calling:
immediately after detach. So, you are showing it and removing it, before event the UI has got the time to update itself. Remove that line from there and rewrite
startDownloads
like this:Here notice that I am calling into the main thread to
hideActivityViewer
because only the main thread can safely useUIKit
.EDIT:
I did not know that you were using Core Data in the download methods...
Have a look at Concurrency with Core Data. You will need to tweak a bit your code by at least using a separate managed object context for your secondary thread (I don't know if it is feasible for you to create the moc there).
Also have a look at this tutorial from Cocoa is my Girlfriend.
As an alternative to all that, you could consider doing:
with:
This does not use threads at all, but I am not sure that the activity viewer will show without any glitch. One more level of hack, if needed, and you could specify a delay in