如何在任务完成块中更新UI?

时间:2011-08-26 13:42:22

标签: cocoa-touch cocoa objective-c-blocks

在我的应用程序中,我在发送HTTP请求之前让进度指示器开始动画。 完成处理程序在块中定义。收到响应数据后,我从块内隐藏进度指示器。我的问题是,正如我所知,UI更新必须在主线程中执行。我怎么能确定它?

如果我在窗口控制器中定义一个更新UI的方法,让块调用方法而不是直接更新UI,那么它是一个解决方案吗?

2 个答案:

答案 0 :(得分:10)

此外,如果您的应用定位到iOS> = 4,则可以使用Grand Central Dispatch:

dispatch_async(dispatch_get_main_queue(), ^{
    // This block will be executed asynchronously on the main thread.
});

当使用performSelect…方法所采用的单选择器和对象参数无法轻松表达自定义逻辑时,这非常有用。

要同步执行一个块,请使用dispatch_sync() - 但请确保您当前没有在主队列上执行,否则GCD将会死锁。

__block NSInteger alertResult; // The __block modifier makes alertResult writable
                               // from a referencing block.
void (^ getResponse)() = ^{
    NSAlert *alert = …;
    alertResult = [NSAlert runModal];
};

if ([NSThread isMainThread]) {
    // We're currently executing on the main thread.
    // We can execute the block directly.
    getResponse();
} else {
    dispatch_sync(dispatch_get_main_queue(), getResponse);
}

// Check the user response.
if (alertResult == …) {
    …
}

答案 1 :(得分:0)

你可能误解了一些东西。使用块并不意味着您的代码在后台线程中运行。有许多插件异步工作(在另一个线程中)并使用块。

有几种方法可以解决您的问题。

您可以使用[NSThread isMainThread]检查您的代码是否在主线程中运行。这有助于您确保自己不在后台。

您还可以使用performSelectorInMainThread:SELperformSelectorInBackground:SEL在主要或后台执行操作。

当您尝试从bakcground线程调用UI时,应用程序会立即崩溃,因此很容易找到错误。