我的情况是文档文件依赖于指向另一个外部媒体文件的链接。打开文档时,我会检查引用的媒体文件是否可用,如果没有,则提示用户找到它。
由于在基于文档的应用程序中将NSOpenPanel显示为工作表非常有意义,我想这样做但是当前线程被阻止是至关重要的,因此在新媒体文件之前不能调用后续代码被选中。
我无法找到一种方法在屏幕上显示此NSOpenPanel作为工作表,同时阻止当前线程。只有[NSOpenPanel runModal]
能够满足我的需求,但这显示为常规对话而非工作表。
似乎这应该是可能的......
答案 0 :(得分:4)
警告:我假设您正在使用沙箱,NSOpenPanel
& NSSavePanel
基于伏都教 - 他们的行为往往因操作系统点释放,月亮阶段,房子里是否有蓝奶酪等等而变化,让他们正常行为可能需要很大的耐心。 (见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:
之后,您的线程进入模态循环,仅处理窗口的事件。当完成处理程序被调用它执行时,它退出该模态循环并返回结果。
无论你做什么,不要尝试将其作为类别添加到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_semaphore_wait
在你的线程上,你应该掌握一个强大的解决方案。
第三
是的我只说了两个,第三个选项是甚至不尝试。
HTH
答案 1 :(得分:0)
NSProgressIndicator上有一个属性,说天气与否,它是不确定的。为了显示进度,您必须将其设置为否