应用模式NSPanel /工作表/对话框+ NSThread ==窗口挂起?

时间:2009-10-18 05:18:36

标签: objective-c cocoa modal-dialog nsthread

我正在调试一个非常不寻常的问题,我想知道是否有人可能对可能出现的问题有所了解:

在NIB的控制器类中,我从同一个NIB中获取NSPanel,然后在NSWindow上模拟显示应用程序(通过代码手工创建):

[[NSApplication sharedApplication] beginSheet: myPanel
                               modalForWindow: window
                                modalDelegate: self
                               didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
                                  contextInfo: nil];
[[NSApplication sharedApplication] runModalForWindow: myPanel];

现在,当单击该工作表上的“完成”按钮时,我运行一些代码来禁用某些按钮并触发一个线程以确保用户输入有效(我必须使用远程服务进行验证)。该线程是从我创建的单独验证器对象中触发的:

// controller calls:
[validator validateCreds: creds
           notify: @selector(validationComplete:)
           onObject: self];

// validator object
validateInfo: (NSDictionary *)parms
      notify: (SEL)notifySelector
    onObject: (id)notifyObject
{
 // build up data with parms and notify info
 [[NSThread detachNewThreadSelector: @selector(remotevalidate:)
            toTarget: self withObject: data];
}

接下来,验证完成后,验证器会通知我的控制器对象:

[notifyObject performSelectorOnMainThread: notifySelector
              withObject: results waitUntilDone: NO];

然后我的控制器对象在验证器对象调用的方法中杀死了对话框:

- (void)validationComplete: (id)data
{
   [[NSApplication sharedApplication] stopModal];
   [createTwitterPanel orderOut: nil];
   [[NSApplication sharedApplication] endSheet: createTwitterPanel
                                      returnCode: NSOKButton];
}

- (void)sheetDidEnd:(NSWindow *)sheet
         returnCode:(int)returnCode
        contextInfo:(void  *)contextInfo
{
    m_returnCode = returnCode;
}

我的问题:虽然面板已关闭/消失,但是在将某个系统事件发送到显示该对话框的窗口之前,顶级NSApp runModalForWindow:不会退出。尝试移动,调整大小或对窗口执行任何操作,或以其他方式切换远离应用程序突然导致方法退出并继续执行。然而,没有多少等待似乎有所帮助。

我已经验证在控制器类上调用的所有方法都是在主应用程序线程上调用的。

更有趣的线索是该对话框有两个控件,一个WebView和一个NSTextField:即使我通过单击窗口强制退出runModalForWindow:,两个控件之间的TABbing仍然搞砸了 - 它根本无法再次运作。这就像我的事件循环被淹没了。

我已经尝试更改validationComplete:而是将通知发布到主线程,并且我还使用waitUntilDone方法上的performSelectorOnMainThread,这一切都没有效果。

有什么想法吗?我应该尝试看哪些事情?

1 个答案:

答案 0 :(得分:2)

来自NSApplication文档:

  

必须使用abortModal代替   stopModal或stopModalWithCode:when   你需要停止一个模态事件循环   来自除标注之外的任何地方   来自那个事件循环。换一种说法,   如果你想停止循环   响应用户的行为   模态窗口,使用stopModal;   否则,请使用abortModal。对于   例如,运行时使用abortModal   在与...不同的主题中   Application Kit的主要线程或何时   回应您拥有的NSTimer   添加到NSModalPanelRunLoopMode   默认NSRunLoop的模式。

所以,我今天学到了一些东西。