5

如果我产生一个新线程,然后在其中我将一个新控制器推送到我的 UINavigationController 上,使用这样的代码......

(a) 不工作

-(void)myCallbackInThread
{
    // move on...
    UIApplication* app = [UIApplication sharedApplication];
    [app changeView];
}

然后我发现视图出现了,但没有响应用户输入。

如果我像这样更改代码

(b) 工作

-(void)myCallbackInThread
{
    // move on...
    UIApplication* app = [UIApplication sharedApplication];
    [app performSelectorOnMainThread:@selector(moveToMain) withObject:nil waitUntilDone:FALSE];
}

然后一切正常。

关于为什么的任何提示?

4

4 回答 4

2

刚刚在 iPhone 线程文档中找到了这个

如果您的应用程序具有图形用户界面,建议您接收与用户相关的事件并从应用程序的主线程启动界面更新。这种方法有助于避免与处理用户事件和绘制窗口内容相关的同步问题。一些框架,例如 Cocoa,通常需要这种行为,但它也具有简化管理用户界面的逻辑的优点。

我仍然看不到实际会导致某些内容显示但无法接收用户输入的原因,但我将来会遵循该指南。

于 2008-10-03T15:42:56.757 回答
2

正如文档所说,“如果您不确定某个特定的图形操作,请计划从您的主线程中执行它。”

一个好的经验法则是,如果一个类没有明确记录为线程安全的,那么它可能不是。此外,未记录为线程安全的代码在被多个线程使用时可能不会很快失败,但可能只是表现出未定义的行为,如您所见。

于 2008-10-03T16:12:43.403 回答
2

在您的情况下,这实际上取决于 [app changeView] 中发生的情况,但它停止响应的原因很可能是您在新的辅助线程上没有运行循环调度事件(更多内容见下文)。然而,一般来说,从辅助线程更新 GUI 是一个非常糟糕的主意。正如您已经发现的那样,所有这些事件都应该通过主线程。

您的第二个示例而不是您的第一个示例有效的主要原因是 UIApplication 在主线程上为您设置和处理运行循环和事件调度程序。因此,当您调用 performSelectorInMainThread 时,选择器会被分派到主运行循环,然后主运行循环能够处理您的 gui 输入和其他事件。事件分派器也由 UIApplication 在主线程上运行和管理。

所以基本上,不要在辅助线程上执行任何 GUI 管理活动。将它们发送到主线程。如果您需要在辅助线程上进行处理(例如计时器或异步调用等),那么您必须在该线程上启动和管理自己的运行循环(有关管理运行循环的更多信息,请参见NSRunLoop)。

于 2008-11-08T00:35:34.020 回答
0

UIKit 或 AppKit 中的 UI 代码几乎都不是线程安全的。它如何失败是无关紧要的,因为如果你担心它是如何失败的,那么你正在做的事情会导致各种奇怪的错误,这些错误无论如何都会在不同的操作系统版本之间发生微妙的变化。

我最好的建议是不要使用后台线程中的东西,除非文档说它是安全的。

于 2008-11-08T01:11:00.313 回答