Cocoa 将NSOpenPanel同步显示为工作表

Cocoa 将NSOpenPanel同步显示为工作表,cocoa,nsopenpanel,Cocoa,Nsopenpanel,我遇到一种情况,文档文件依赖于指向另一个外部媒体文件的链接。打开文档时,我会检查引用的媒体文件是否可用,如果不可用,则会提示用户查找该文件 由于在基于文档的应用程序中将NSOpenPanel显示为工作表是非常有意义的,因此我想这样做,但当前线程被阻止是至关重要的,因此在选择新媒体文件之前,无法调用后续代码 在阻止当前线程时,我找不到在文档窗口中将此NSOpenPanel显示为工作表的方法。只有[NSOpenPanel runModal]可以满足我的需要,但它显示为常规对话框而不是工作表 这似乎在

我遇到一种情况,文档文件依赖于指向另一个外部媒体文件的链接。打开文档时,我会检查引用的媒体文件是否可用,如果不可用,则会提示用户查找该文件

由于在基于文档的应用程序中将NSOpenPanel显示为工作表是非常有意义的,因此我想这样做,但当前线程被阻止是至关重要的,因此在选择新媒体文件之前,无法调用后续代码

在阻止当前线程时,我找不到在文档窗口中将此NSOpenPanel显示为工作表的方法。只有
[NSOpenPanel runModal]
可以满足我的需要,但它显示为常规对话框而不是工作表


这似乎在某种程度上是可能的…

警告:我假设您正在使用沙箱,因此
NSOpenPanel
&
NSSavePanel
基于巫毒-他们的行为往往会因操作系统点释放、月亮相位、房子里是否有蓝色奶酪而有所不同,让他们表现正常需要很大的耐心。(见。)是的,我是在开玩笑——有一点——但是你已经被警告过了

还在这儿吗

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

所有代码都只是输入到答案中,除了打字错误

第一:

+ (NSInteger) myRunModal:(NSOpenPanel *)myPanel
        asSheetForWindow:(NSWindow *)myWindow
{
   [myPanel beginSheetModalForWindow:myWindow
                   completionHandler:^(NSInteger result)
                                     {
                                        [NSApp stopModalWithCode:result];
                                     }
   ];
   return [NSApp runModalForWindow:myWindow];
}
在调用
beginSheetModalForWindow:
之后,线程进入一个仅处理窗口事件的模式循环。当完成处理程序被调用并执行时,它将退出该模式循环并返回结果

无论您做什么,都不要尝试将其作为类别添加到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
的代码在线程上运行,然后安排
beginSheetModalForWindow:
在线程上使用
dispatch\u semaphore\u wait
在主线程上运行,那么您应该掌握一个健壮的解决方案

第三:

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


HTH

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

我完全理解您的回答的深度,但由于这是一个罕见的事件,我认为我将接受UI不一致性,并选择您的选项3!