如果我生成一个新线程,然后在其中我将一个新控制器推到我的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];
}
然后一切正常。
有关原因的任何提示?
答案 0 :(得分:2)
刚刚在iPhone线程文档中找到了这个
如果您的应用程序有图形 用户界面,建议 您收到与用户相关的事件和 启动您的界面更新 应用程序的主要线程。这个 方法有助于避免同步 与处理用户相关的问题 事件和绘图窗口内容。 一些框架,如Cocoa, 通常需要这种行为,但是 它也有优势 简化管理逻辑 你的用户界面。
我仍然没有看到实际会导致某些内容显示但无法接收用户输入的内容,但我将来会遵循该指南。
答案 1 :(得分:2)
正如文档所说,“如果您不确定某个特定的图形操作,请计划从主线程中执行此操作。”
一个好的经验法则是,如果一个类没有明确记录为线程安全的,那么它可能不是。此外,未被记录为线程安全的代码在被多个线程使用时可能不会快速失败,但可能只是表现出未定义的行为,如您所见。
答案 2 :(得分:2)
在你的情况下,它实际上取决于[app changeView]中发生了什么,但它停止响应的原因很可能是你的新的辅助线程上没有运行循环调度事件(下面有更多内容)。但是,一般来说,从辅助线程更新GUI是一个非常糟糕的主意。正如您已经发现的那样,所有这些事件都应该通过主线程。
第二个示例工作的主要原因而不是您的第一个示例是UIApplication在主线程上为您设置并处理运行循环和事件调度程序。因此,当您调用performSelectorInMainThread时,选择器将被分派到主运行循环,然后该运行循环能够处理您的gui输入和其他事件。事件调度程序也由UIApplication在主线程上运行和管理。
基本上,不要在辅助线程上执行任何GUI管理活动。将这些发送到主线程。如果你需要在辅助线程上进行处理(对于定时器或异步调用等),那么你必须在该线程上启动和管理自己的运行循环(有关管理运行循环的更多信息,请参阅NSRunLoop) )。
答案 3 :(得分:0)
UIKit或AppKit中几乎没有任何UI代码是线程安全的。它如何失败是无关紧要的,因为如果你担心它是如何失败的,那么你正在做一些会导致各种奇怪错误的东西,无论如何都会在不同的操作系统发布之间巧妙地改变。
我最好的建议是不要使用后台线程中的东西,除非文档说它是安全的。