如何让DropboxAPI在runModalForWindow中工作

时间:2014-08-14 14:25:47

标签: cocoa dropbox nswindow

我正在使用Dropbox API for OSX。一切正常,除非我想在以[NSApp runModalForWindow:thisWindow]开头的模态窗口中进行调用;似乎模态循环阻止了 DropboxAPI处理任何东西。 永远不会调用DBRestClient委托方法来响应例如[client loadMetadata:path];这是 - 如果理解正确 - 符合NSApplication文档对此方法所说的内容。问题是: 有没有办法让Dropbox的调用工作在模态窗口内? 我已经看到计时器可以添加到NSModalPanelRunLoopMode中。是否有类似DroboxAPI的东西?

另外:在此显示或任何其他模态窗口显示之前已启动但尚未完成的Dropbox调用会正常进行,还是会被阻止?

是;进一步调查显示任何runModalForWindow甚至显示NSAlert.showModal都将完全阻止DropboxAPI。此外,inplace鼠标处理循环也做同样的事情。 Imo是OSX DropboxAPI的一个主要设计缺陷:它本应该在后台线程上运行。解决这个问题的唯一方法是不启动任何用户任务,这可能涉及阻止Dropbox,而API仍在运行。对于需要Dropbox在后台运行的任何非平凡应用程序而言,这是不可行的。

3 个答案:

答案 0 :(得分:1)

NSApplication runModalForWindow的实现确实太苛刻了。

这是更人性化的版本:

void runWindowModal(NSWindow* pnw) {

        [pnw retain];

        NSApplication* app = [NSApplication sharedApplication];

        NSModalSession session = [app beginModalSessionForWindow:pnw];

        for( ;; ) {
          if ([app runModalSession:session] != NSModalResponseContinue)
             break;

          NSEvent* e = [app nextEventMatchingMask: NSAnyEventMask
                                        untilDate: [NSDate distantFuture]
                                           inMode: NSDefaultRunLoopMode
                                          dequeue: YES];
          if (e != nil)
           [app sendEvent: e];
        }

        [app endModalSession: session];

        [pnw release];

}

这将在运行模态循环时启用NSURLConnection和其他回调处理。

答案 1 :(得分:0)

Dropbox支持刚刚确认OSX上的DropboxAPI在主runloop上工作,而且runModalForWindow等也会阻止API。没有解决方法。

答案 2 :(得分:0)

问题更为笼统。所有nsurl连接只能在主runloop上运行。这意味着webview具有相同的问题。并且有一个解决方案。您必须经常创建一个模态会话并在短时间内运行它,并将主线程锁定在一个循环中,直到关闭模态窗口。每次切换回模态会话时,主runloop将完成任何计划任务,包括模态会话中的nsurlconnections。

现在我将向您展示一段代码,但请注意,这是使用Xamarin.Mac库的c#。您应该能够轻松地将其转换为objc。但如果您觉得困难,可以在模态对话框中查找nswebview的解决方案。

//so this is in my NSWindowController - the modal dialog
IntPtr session;
bool running;

public void showDialog ()//this is the method I use to show the dialog
{
    running = true;
    session = NSApplication.SharedApplication.BeginModalSession (Window);
    int resp = (int)NSRunResponse.Continues;

    while (running && resp == (int)NSRunResponse.Continues) {
        resp = (int)NSApplication.SharedApplication.RunModalSession (session);
        NSRunLoop.Current.RunUntil (NSRunLoopMode.Default, NSDate.DistantFuture);
    }
    NSApplication.SharedApplication.EndModalSession (session);
}

[Export ("windowWillClose:")]
public void WindowWillClose (NSNotification notification)//this is the override of windowWillClose:
{
    running = false;
}