将 NSOpenPanel 同步呈现为 sheet

Presenting NSOpenPanel as sheet synchronously

我有一个文档文件依赖于 link 到另一个外部媒体文件的情况。打开文档时,我会检查引用的媒体文件是否可用,如果不可用,则会提示用户找到它。

因为在基于文档的应用程序中将 NSOpenPanel 显示为 sheet 非常有意义,所以我想这样做,但当前线程被阻塞是至关重要的,因此后续代码无法执行调用直到选择新的媒体文件。

我无法找到在文档 window 上将此 NSOpenPanel 显示为 sheet 的方法,同时阻塞当前线程。只有 [NSOpenPanel runModal] 可以满足我的需要,但这显示为常规对话框而不是 sheet。

看来这应该是可行的...

警告: 我假设您正在使用沙箱,所以 NSOpenPanelNSSavePanel 是基于巫术的 - 它们的行为往往因 OS 点释放、月相、房子里是否有蓝纹奶酪等,让它们表现正常需要很大的耐心。 (参见 this question for one person's recent pain。)是的,我在开玩笑 - 有点 - 但 你已经被警告过

还在吗?

已知类似于以下两个的代码在某个时间点工作,在满月和午夜过后的质数秒期间。

所有代码都刚刚输入到答案中,预计有错别字。

第一个:

+ (NSInteger) myRunModal:(NSOpenPanel *)myPanel
        asSheetForWindow:(NSWindow *)myWindow
{
   [myPanel beginSheetModalForWindow:myWindow
                   completionHandler:^(NSInteger result)
                                     {
                                        [NSApp stopModalWithCode:result];
                                     }
   ];
   return [NSApp runModalForWindow:myWindow];
}

在调用 beginSheetModalForWindow: 后,您的线程进入模态循环,只处理 window 的事件。当调用完成处理程序时,它会执行它退出该模式循环并返回结果。

无论您做什么,都不要 尝试将此作为类别添加到 NSOpen/SavePanel 类。那种方式会导致疯狂。记住他们是巫毒教,不要以任何方式直接惹恼他们。

第二个:

使用信号量,一方面这看起来很明显,另一方面立即想到死锁...

+ (void) myRunModal:(NSOpenPanel *)myPanel
   asSheetForWindow:(NSWindow *)myWindow
  completionHandler:(void (^)(NSInteger))myHandler
{
   // Use a semaphore to block thread till sheet is done
   dispatch_semaphore_t sema = dispatch_semaphore_create(0);
   [myPanel beginSheetModalForWindow:myWindow
                   completionHandler:^(NSInteger result)
                                     {
                                        myHandler(result);
                                        // Unblock caller
                                        dispatch_semaphore_signal(sema);
                                     }
   ];
   // Block until sheet completes
   dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}

此处您的线程等待信号量发出信号。如果系统想在同一个线程上执行处理程序,你就会陷入僵局。它会尝试吗?也许。

但是,如果您可以安排您的代码,使需要调用 NSOpenPanel 的代码在线程上 运行ning,则安排 beginSheetModalForWindow: 到 运行 在主线程上与 dispatch_semaphore_wait 在您的线程上,那么您应该掌握一个可靠的解决方案。

第三名:

是的,我只说了两个,第三个选项是不要尝试

HTH

NSProgressIndicator 上有一个属性表明天气与否是不确定的。为了显示进度,您必须将其设置为 NO