【问题标题】:Pumping Cocoa message loop from background thread从后台线程抽取 Cocoa 消息循环
【发布时间】:2012-02-07 10:27:38
【问题描述】:

我有一个基于 Cocoa 的命令行应用程序,它以编程方式创建一个 NSWindow + NSView。它使用 nextEventMatchingMask 循环来手动泵送事件循环和调度事件。这个循环被一些上层代码周期性地调用来轮询输入。

如果我在主线程上运行所有内容,那么这可以正常工作,因为视图可以正确接收输入事件。

如果我将窗口创建和消息循环移动到单独的线程,则 nextEventMatchingMask 不再返回任何事件并且视图不会接收输入。

我知道只有 Cocoa 应用程序中的“主”线程应该处理事件。然而,这个辅助线程是唯一需要与 Cocoa 对话的线程,所以就 Cocoa 而言,我想将它用作“主”线程。这可能吗?我从这个线程调用 NSApplicationLoad,据我所知,这是进程中调用的第一个 Cocoa 函数。

如果我不能指定哪个是主 Cocoa 线程,那么有没有其他方法可以在后台线程上创建一个 NSWindow 并为其接收事件?我无法执行调用 NSApplication Run 之类的操作,因为我无法控制应用程序的主循环。当上层代码请求我这样做时,我只需要从窗口中提取输入事件。

【问题讨论】:

标签: macos cocoa


【解决方案1】:

也许您需要在辅助线程上启动 runloop。在你的主线程中,当你产生你的辅助线程时,调用这样的东西:

[NSThread detachNewThreadSelector:@selector(launchThread) 
                         toTarget:[ThreadHandler class] 
                       withObject:nil];

在 ThreadHandler 类中,有如下内容:

+ (void)launchThread
{
    NSRunLoop *threadRunLoop = [NSRunLoop currentRunLoop];
    while (someThreadExitCondition && [threadRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]);
}

这应该启动你的线程运行循环处理事件。如果不测试这是否允许您处理在辅助线程中创建的窗口的事件,我不确定,但它可能会让您开始了解如何运行线程的 runloop。您甚至可以设置类似于分布式对象的情况,您可以通过 NSConnection 从主事件循环将事件泵送到辅助线程 (example)。希望这至少可以为您提供另一种追求的途径。

【讨论】:

  • 感谢您的建议。然而,额外的问题是,这个辅助线程是一个 posix 线程,而不是一个 NSThread,并且不是由我管理的。当它希望我检查事件时,它会定期调用我正在处理的代码,这样我就不能让它进入任何阻塞的运行循环。也许我可以尝试按照您的描述生成我自己的事件处理线程,然后以某种方式将已处理的事件(假设我可以获取它们)编组回认为它正在执行事件处理的线程。
【解决方案2】:

这不是我会依赖的行为。

如果您需要在不受运行循环限制的线程上运行后端,请在辅助线程上运行它,以便从主线程运行 UI。

或者,您可以创建另一个进程...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2011-12-06
    • 1970-01-01
    • 2011-05-19
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多