2012-12-04 61 views
1

我有一个Swing应用程序,并进行JNI方法调用,打开NSOpenPanel。在一些电脑上(我不知道它们之间有什么相似之处),它完全挂起了应用程序。在大多数电脑上它的工作正常。如果代码将应用程序挂在特定的Mac上,则每次执行时都会执行该代码。NSOpenPanel挂起java应用程序

这里是我如何开一个NSOpenPanel:

JNF_COCOA_ENTER(env);  
// My helper Obj-c object to make a selector call 
OpenFileObject *openFile = [[OpenFileObject alloc] init];  
if ([NSThread isMainThread]) 
    [openFile showOpenFileDialog]; 
else 
    [JNFRunLoop performOnMainThread:@selector(showOpenFileDialog) on:openFile withObject:nullptr waitUntilDone:TRUE]; 
// ...Handles results  
JNF_COCOA_EXIT(env); 

这里是showOpenFileDialog方法:

NSOpenPanel *panel = [NSOpenPanel openPanel]; 
[panel setCanChooseFiles:canChooseFiles]; 
[panel setCanChooseDirectories:canChooseFolders]; 
[panel setAllowsMultipleSelection:allowMultiSelection]; 
[panel setAllowedFileTypes:fileTypes]; 
[panel setTitle:dialogTitle]; 

if ([panel runModal] == NSFileHandlingPanelOKButton) 
    urls = [[panel URLs] copy]; 
else 
    urls = nullptr; 

,这里是挂起报告:https://gist.github.com/4207956

任何想法?

回答

1

首先,我怀疑这有什么关系你的问题,但我会谨慎使用nullptrTRUE的作为参数传递给performOnMainThread:...相反,我会做:

[JNFRunLoop performOnMainThread:@selector(showOpenFileDialog) on:openFile withObject:nil waitUntilDone:YES];

只要是在安全的一面。

从堆栈跟踪中,假设这是一个大堆栈,并且您将它分开以添加有关您的帮助对象方法调用的注释,似乎正在采用的代码路径是[NSThread isMainThread]返回NO的代码路径。这意味着它在后台线程上(__NSThreadPerformPerform然后执行JNFRunLoop的出价)。

堆栈永远不会从NSOpenPanel的初始化路径中跳出,并以某种方式深入底层,它再次访问运行循环的东西。在我看来,似乎发生了某种僵局。

如果JNFRunLoop在另一个线程等待的showOpenFileDialog方法的执行来完成对主运行循环,并在东西是openPanel试图等待在同一运行循环的事情,这可能导致死锁。

我不熟悉Java和Cocoa之间的集成,但可能有一些方法可以避免在非主线程上执行第一个代码片段?

或者,你可以尝试使用:

[openFile performSelectorOnMainThread:@selector(showOpenFileDialog) withObject:nil waitUntilDone:YES];

在非主线程路径

+0

可能是不相关的,但由于缓冲区溢出,我确实在类似的堆栈中发现了这样的崩溃:http://www.cocoabuilder.com/archive/cocoa/130423-nssavepanel-crashing-on-instantiation.html – lyricsboy