我遇到一个文档文件依赖于另一个外部媒体文件的链接的情况。打开文档后,我检查参考媒体文件是否可用,如果没有,则会提示用户查找它。
由于在基于文档的应用程序中将NSOpenPanel显示为表格非常合理,因此我想这样做,但是阻止当前线程至关重要,因此在选择新的媒体文件之前,无法调用任何后续代码。
我找不到在阻止当前线程时在文档窗口上以表格形式显示此NSOpenPanel的方法。只有[NSOpenPanel runModal]
可以满足我的需要,但是显示为常规对话框而不是工作表。
看来这应该是可能的...
最佳答案
警告:我假设您使用的是沙盒,所以NSOpenPanel
和NSSavePanel
是基于伏都教的-它们的行为会因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:
之后,您的线程进入一个模态循环,仅处理窗口事件。当完成处理程序被调用时,它执行并退出该模式循环,并返回结果。无论您做什么,都不要尝试将其作为类别添加到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
在线程上运行,那么可以采用一种可靠的解决方案应该掌握在你手中。第三:
是的,我只说了两个,第三个选择是甚至不要尝试。
高温超导
关于cocoa - 将NSOpenPanel同步显示为工作表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28478020/