将 NSOpenPanel 同步呈现为 sheet
Presenting NSOpenPanel as sheet synchronously
我有一个文档文件依赖于 link 到另一个外部媒体文件的情况。打开文档时,我会检查引用的媒体文件是否可用,如果不可用,则会提示用户找到它。
因为在基于文档的应用程序中将 NSOpenPanel 显示为 sheet 非常有意义,所以我想这样做,但当前线程被阻塞是至关重要的,因此后续代码无法执行调用直到选择新的媒体文件。
我无法找到在文档 window 上将此 NSOpenPanel 显示为 sheet 的方法,同时阻塞当前线程。只有 [NSOpenPanel runModal]
可以满足我的需要,但这显示为常规对话框而不是 sheet。
看来这应该是可行的...
警告: 我假设您正在使用沙箱,所以 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:
后,您的线程进入模态循环,只处理 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
我有一个文档文件依赖于 link 到另一个外部媒体文件的情况。打开文档时,我会检查引用的媒体文件是否可用,如果不可用,则会提示用户找到它。
因为在基于文档的应用程序中将 NSOpenPanel 显示为 sheet 非常有意义,所以我想这样做,但当前线程被阻塞是至关重要的,因此后续代码无法执行调用直到选择新的媒体文件。
我无法找到在文档 window 上将此 NSOpenPanel 显示为 sheet 的方法,同时阻塞当前线程。只有 [NSOpenPanel runModal]
可以满足我的需要,但这显示为常规对话框而不是 sheet。
看来这应该是可行的...
警告: 我假设您正在使用沙箱,所以 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:
后,您的线程进入模态循环,只处理 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