connectionDidFinishLoading - 如何强制更新UIView?

时间:2010-01-03 10:09:32

标签: iphone nsurlconnection

我可以从互联网上下载ZIP文件。后处理在connectionDidFinishLoading中完成,并且工作正常,但不更新任何UIView元素。例如,我设置statusUpdate.text = @“解压缩文件”,但直到connectionDidFinishLoading完成后才会出现该更改。同样,在此方法结束之前,UIProgressView和UIActivityIndi​​catorView对象不会更新。

有没有办法在此方法中强制更新UIView?我尝试设置[self.view setNeedsDisplay],但这不起作用。它似乎在主线程中运行。这里的所有其他命令都可以正常工作 - 唯一的问题是更新UI。

谢谢!

更新:这里是不更新UIVIEW的代码:

-(void)viewWillAppear:(BOOL)animated {
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(processUpdate:) userInfo:nil repeats:YES];
    downloadComplete = NO;
    statusText.text = @"";

}

-(void)processUpdate:(NSTimer *)theTimer {
    if (! downloadComplete) {
        return;
    }

    [timer invalidate];
    statusText.text = @"Processing update file."; 
    progress.progress = 0.0;
        totalFiles = [newFiles count];
    for (id fileName in newFiles) {
        count++;
            progress.progress = (float)count / (float)totalFiles;
        // ... process code goes here ...
         }
}

在processUpdate结束时,我设置了downloadComplete = YES。这构建&运行没有错误并按预期工作,除非在processUpdate完成之后UIVIEW中没有任何更新,然后一切都会立即更新。

到目前为止,感谢您的帮助!

5 个答案:

答案 0 :(得分:1)

正如Niels所说,如果要查看视图更新,则必须将控制权返回到运行循环。但是除非你真的需要,否则不要开始分离新线程。我推荐这种方法:

- (void)connectionDidFinishLoading:(NSConnection *)connection {
    statusUpdate.text = @"Uncompressing file";
    [self performSelector:@selector(doUncompress) withObject:nil afterDelay:0];
}

- (void)doUncompress {
    // Do work in 100 ms chunks
    BOOL isFinished = NO;
    NSDate *breakTime = [NSDate dateWithTimeIntervalSinceNow:100];
    while (!isFinished && [breakTime timeIntervalSinceNow] > 0) {
        // do some work
    }
    if (! isFinished) {
        statusUpdate.text = // here you could update with % complete
        // better yet, update a progress bar
        [self performSelector:@selector(doUncompress) withObject:nil afterDelay:0];
    } else {
        statusUpdate.text = @"Done!";
        // clean up
    }
}

基本的想法是你做小块工作。从方法返回以允许运行循环定期执行。对performSelector的调用:将确保控件最终返回到您的对象。

请注意,执行此操作的风险是用户可能按某个按钮或以某种您可能不期望的方式与UI进行交互。在你工作的时候调用UIApplication的beginIgnoringInteractionEvents忽略输入可能会有所帮助......除非你想要非常好并提供一个取消按钮来设置你在doUncompress方法中检查的标志...

您也可以尝试自己运行运行循环,经常调用[[NSRunLoop currentRunLoop] runUntilDate:...],但我从未在自己的代码中尝试过。

答案 1 :(得分:0)

当你处于connectionDidFinishLoading时,在应用程序运行循环中没有其他任何事情发生。控件需要传递回运行循环,以便它可以协调UI更新。

只需将数据传输标记为完成,并将视图标记为更新。将下载数据的任何繁重处理推迟到它自己的线程。

应用程序将调用您的视图,让他们稍后在运行循环中刷新其内容。根据需要在您自己的自定义视图上实现drawRect。

答案 2 :(得分:0)

如果你在主线程中收到connectionDidFinishLoading,那你就不走运了。除非您从此方法返回,否则UI中不会刷新任何内容。

另一方面,如果您在单独的线程中运行连接,则可以使用以下代码安全地更新UI:

UIProgressView *prog = ... <your progress view reference> ...
[prog performSelectorOnMainThread:@selector(setProgress:)
                       withObject:[NSNumber numberWithFloat:0.5f]
                    waitUntilDone:NO];

小心不要从非主线程更新UI - 始终使用performSelectorOnMainThread方法!

答案 3 :(得分:0)

完全按照计时器执行操作,只需使用ConnectionDidFinish将处理代码发送到新线程:定时器可以更新UI,因为它们是从主线程运行的。

答案 4 :(得分:0)

问题是,在for()循环中未更新UI。有关简单的解决方案,请参阅the answer in this thread