iOS - 后台进程和UI更新

时间:2011-08-04 08:44:29

标签: ios background nsthread nsoperation nsoperationqueue

问题很简单:我的app控制每次启动时是否有更新。如果有更新,弹出窗口将显示“是”或“否”选择。当用户点击是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方法并显示微调器。

谢谢:)

1 个答案:

答案 0 :(得分:5)

首先要做的事情。您不需要启动4个操作,因为您已经在辅助线程中并且不需要并行执行4个操作。你可以这样做:

-(void)startDownloads {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
    [self downloadControlAndUpdatePoi];
    [self downloadControlAndUpdateItinerari];
    [self downloadControlAndUpdateArtisti];
    [self downloadControlAndUpdateEventi];
    [pool release];
}

最重要的是,如果您在startDownloads方法中使用autorelease,则需要在downloadControl*中定义自动释放池,否则我怀疑您会有泄漏。

至于活动指示器未显示的原因,取决于您正在呼叫的事实:

    [self hideActivityViewer];
分离后立即

。因此,您在显示它并将其删除之前,UI已经有时间更新自己。从那里删除该行并重写startDownloads,如下所示:

-(void)startDownloads {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
    [self downloadControlAndUpdatePoi];
    [self downloadControlAndUpdateItinerari];
    [self downloadControlAndUpdateArtisti];
    [self downloadControlAndUpdateEventi];
    [self performSelectorOnMainThread:@selector(hideActivityViewer) withObject:nil waitUntilDone:NO];  

    [pool release];
}

这里注意到我正在调用hideActivityViewer的主线程,因为只有主线程可以安全地使用UIKit。 编辑:

我不知道您在下载方法中使用了Core Data ...

看看Concurrency with Core Data。您需要通过至少为辅助线程使用单独的托管对象上下文来调整您的代码(我不知道您是否可以在那里创建moc)。

另请查看this tutorial from Cocoa is my Girlfriend

作为所有这些的替代方案,您可以考虑:

if (buttonIndex==1) {
    [self showActivityViewer];
    [self performSelector:@selector(startDownloads) withObject:nil afterDelay:0];
    NSLog(@"AGGIORNA");
} else {
    NSLog(@"NON AGGIORNARE");
    return;
}

使用:

-(void)startDownloads {
    [self downloadControlAndUpdatePoi];
    [self downloadControlAndUpdateItinerari];
    [self downloadControlAndUpdateArtisti];
    [self downloadControlAndUpdateEventi];
    [self hideActivityViewer];  
}

这根本不使用线程,但我不确定活动查看器是否会显示没有任何故障。如果需要,还有一个级别的黑客攻击,你可以在

中指定延迟
[self performSelector:@selector(startDownloads) withObject:nil afterDelay:0.1];
相关问题