iOS - 后台进程和UI更新

And*_*ino 3 background nsoperation nsthread nsoperationqueue ios

问题很简单:我的应用程序控制每次启动时是否有更新.如果有更新,弹出窗口将显示是或否选择.当用户点击是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是有一个问题:当用户点击是时,警报不会消失并保留在屏幕上,直到所有方法都完成.所以我尝试这个其他代码:

-(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];

}
Run Code Online (Sandbox Code Playgroud)

即使在这里也存在问题:我点按开始,但活动查看器不会出现.警报消失,线程一个接一个地启动并运行4个方法.

我需要在后台运行的进程,就像我的第二个代码一样,但我甚至需要运行showActityViewer方法并显示微调器.

谢谢 :)

ser*_*gio 5

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

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

最重要的是,startDownloads如果你autoreleasedownloadControl*方法中使用,你需要定义一个自动释放池,否则我怀疑你会有泄漏.

至于为什么活动指标没有出现,这取决于你打电话的事实:

    [self hideActivityViewer];
Run Code Online (Sandbox Code Playgroud)

分离后立即.因此,您在显示它并将其删除之前,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];
}
Run Code Online (Sandbox Code Playgroud)

这里注意我调用主线程,hideActivityViewer因为只有主线程可以安全使用UIKit.编辑:

我不知道你在下载方法中使用的是Core Data ...

看看核心数据的并发性.您需要通过至少为辅助线程使用单独的托管对象上下文来调整您的代码(我不知道您是否可以在那里创建moc).

另外看看Cocoa的这个教程是我的女朋友.

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

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

有:

-(void)startDownloads {
    [self downloadControlAndUpdatePoi];
    [self downloadControlAndUpdateItinerari];
    [self downloadControlAndUpdateArtisti];
    [self downloadControlAndUpdateEventi];
    [self hideActivityViewer];  
}
Run Code Online (Sandbox Code Playgroud)

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

[self performSelector:@selector(startDownloads) withObject:nil afterDelay:0.1];
Run Code Online (Sandbox Code Playgroud)