2

我可以从 Internet 下载 ZIP 文件。后处理在 connectionDidFinishLoading 中完成,并且工作正常,除了没有更新 UIView 元素。例如,我设置了 statusUpdate.text = @"Uncompressing file" 但直到 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 中没有任何更新,然后所有内容立即更新。

感谢您一直以来的帮助!

4

5 回答 5

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 交互。beginIgnoringInteractionEvents在您工作时调用 UIApplication 忽略输入可能会有所帮助...除非您想变得非常好并提供一个取消按钮来设置您在doUncompress方法中签入的标志...

您也可以尝试自己运行运行循环,[[NSRunLoop currentRunLoop] runUntilDate:...]每隔一段时间调用一次,但我从未在自己的代码中尝试过。

于 2010-01-08T20:12:45.627 回答
0

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

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

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

注意不要从非主线程更新 UI - 始终使用该performSelectorOnMainThread方法!

于 2010-01-08T07:28:28.263 回答
0

当您在 connectionDidFinishLoading 中时,应用程序运行循环中不会发生任何其他事情。需要将控制权传递回运行循环,以便它可以协调 UI 更新。

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

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

于 2010-01-03T10:36:11.443 回答
0

问题是 UI 没有for()循环更新。请参阅此线程中的答案以获得简单的解决方案!

于 2012-12-09T18:09:42.443 回答
0

准确地使用计时器执行您正在执行的操作,只需使用 ConnectionDidFinish: 将您的处理代码分派到一个新线程:。计时器可以更新 UI,因为它们是从主线程运行的。

于 2011-10-12T04:39:50.537 回答