NSSavePanel在沙盒应用OS X 10.10中崩溃

时间:2014-10-14 17:28:17

标签: objective-c cocoa sandbox nssavepanel

我在沙盒应用程序中使用OS X 10.10中的NSSavePanel让用户选择文件的保存位置(非常标准),但是当我打电话时应用程序崩溃:

NSSavePanel *panel = [NSSavePanel savePanel];

我在调试器中得到了这个:

2014-10-14 18:22:16.019 Farm Hand[2807:942766] an error occurred while attempting to connect to listener 'com.apple.view-bridge': Connection interrupted
2014-10-14 18:22:16.020 Farm Hand[2807:942766] *** Assertion failure in +[NSXPCSharedListener connectionForListenerNamed:fromServiceNamed:], /SourceCache/ViewBridge/ViewBridge-99/NSXPCSharedListener.m:394
2014-10-14 18:22:16.023 Farm Hand[2807:942766] An uncaught exception was raised
2014-10-14 18:22:16.023 Farm Hand[2807:942766] NSXPCSharedListener unable to create endpoint for listener named com.apple.view-bridge
2014-10-14 18:22:16.023 Farm Hand[2807:942766] (
    0   CoreFoundation                      0x00007fff8880364c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff9390e6de objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8880342a +[NSException raise:format:arguments:] + 106
    3   Foundation                          0x00007fff8a3a65b9 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
    4   ViewBridge                          0x00007fff964e40b8 +[NSXPCSharedListener connectionForListenerNamed:fromServiceNamed:] + 151
    5   ViewBridge                          0x00007fff964c2981 -[NSRemoteViewBase serviceMarshalConnection] + 286
    6   ViewBridge                          0x00007fff964c36ae -[NSRemoteViewBase advanceToConfigPhase:awaitingWindowRights:] + 414
    7   ViewBridge                          0x00007fff964d1f7b -[NSWindowCentricRemoteView advanceToConfigPhase] + 947
    8   ViewBridge                          0x00007fff964c4223 -[NSRemoteViewBase viewServiceMarshalProxy:withErrorHandler:] + 88
    9   ViewBridge                          0x00007fff964ba8a8 -[NSRemoteViewBase bridge] + 207
    10  AppKit                              0x00007fff8e859b9d -[NSVBSavePanel init] + 303
    11  AppKit                              0x00007fff8e5a8ec1 +[NSSavePanel newRemotePanel] + 301
    12  AppKit                              0x00007fff8e5a8f53 +[NSSavePanel _crunchyRawUnbonedPanel] + 74
    13  Farm Hand                           0x000000010009526d __40-[RHFlockHomeViewController exportTable]_block_invoke_3 + 109
    14  libdispatch.dylib                   0x00000001002202bb _dispatch_call_block_and_release + 12
    15  libdispatch.dylib                   0x000000010021ad43 _dispatch_client_callout + 8
    16  libdispatch.dylib                   0x0000000100229d9f _dispatch_main_queue_callback_4CF + 1370
    17  CoreFoundation                      0x00007fff88756c59 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    18  CoreFoundation                      0x00007fff887132ef __CFRunLoopRun + 2159
    19  CoreFoundation                      0x00007fff88712838 CFRunLoopRunSpecific + 296
    20  HIToolbox                           0x00007fff94ec743f RunCurrentEventLoopInMode + 235
    21  HIToolbox                           0x00007fff94ec71ba ReceiveNextEventCommon + 431
    22  HIToolbox                           0x00007fff94ec6ffb _BlockUntilNextEventMatchingListInModeWithFilter + 71
    23  AppKit                              0x00007fff8e006821 _DPSNextEvent + 964
    24  AppKit                              0x00007fff8e005fd0 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194
    25  AppKit                              0x00007fff8dff9f73 -[NSApplication run] + 594
    26  AppKit                              0x00007fff8dfe5424 NSApplicationMain + 1832
    27  Farm Hand                           0x0000000100010552 main + 34
    28  libdyld.dylib                       0x00007fff8d7e85c9 start + 1
)
2014-10-14 18:22:16.027 Farm Hand[2807:942766] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSXPCSharedListener unable to create endpoint for listener named com.apple.view-bridge'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff8880364c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff9390e6de objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8880342a +[NSException raise:format:arguments:] + 106
    3   Foundation                          0x00007fff8a3a65b9 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
    4   ViewBridge                          0x00007fff964e40b8 +[NSXPCSharedListener connectionForListenerNamed:fromServiceNamed:] + 151
    5   ViewBridge                          0x00007fff964c2981 -[NSRemoteViewBase serviceMarshalConnection] + 286
    6   ViewBridge                          0x00007fff964c36ae -[NSRemoteViewBase advanceToConfigPhase:awaitingWindowRights:] + 414
    7   ViewBridge                          0x00007fff964d1f7b -[NSWindowCentricRemoteView advanceToConfigPhase] + 947
    8   ViewBridge                          0x00007fff964c4223 -[NSRemoteViewBase viewServiceMarshalProxy:withErrorHandler:] + 88
    9   ViewBridge                          0x00007fff964ba8a8 -[NSRemoteViewBase bridge] + 207
    10  AppKit                              0x00007fff8e859b9d -[NSVBSavePanel init] + 303
    11  AppKit                              0x00007fff8e5a8ec1 +[NSSavePanel newRemotePanel] + 301
    12  AppKit                              0x00007fff8e5a8f53 +[NSSavePanel _crunchyRawUnbonedPanel] + 74
    13  Farm Hand                           0x000000010009526d __40-[RHFlockHomeViewController exportTable]_block_invoke_3 + 109
    14  libdispatch.dylib                   0x00000001002202bb _dispatch_call_block_and_release + 12
    15  libdispatch.dylib                   0x000000010021ad43 _dispatch_client_callout + 8
    16  libdispatch.dylib                   0x0000000100229d9f _dispatch_main_queue_callback_4CF + 1370
    17  CoreFoundation                      0x00007fff88756c59 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    18  CoreFoundation                      0x00007fff887132ef __CFRunLoopRun + 2159
    19  CoreFoundation                      0x00007fff88712838 CFRunLoopRunSpecific + 296
    20  HIToolbox                           0x00007fff94ec743f RunCurrentEventLoopInMode + 235
    21  HIToolbox                           0x00007fff94ec71ba ReceiveNextEventCommon + 431
    22  HIToolbox                           0x00007fff94ec6ffb _BlockUntilNextEventMatchingListInModeWithFilter + 71
    23  AppKit                              0x00007fff8e006821 _DPSNextEvent + 964
    24  AppKit                              0x00007fff8e005fd0 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194
    25  AppKit                              0x00007fff8dff9f73 -[NSApplication run] + 594
    26  AppKit                              0x00007fff8dfe5424 NSApplicationMain + 1832
    27  Farm Hand                           0x0000000100010552 main + 34
    28  libdyld.dylib                       0x00007fff8d7e85c9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

这是我的完整代码:

if ([format isEqualToString:@".csv"]) {
            loadingBar = [RHLoadingBar loadingBarWithMessage:@"Preparing File..."];
            [loadingBar showModally];
            [loadingBar start];
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                NSString *string = [[RHFileController sharedController] CSVTableWithObject:sheepArrayController.arrangedObjects propertyKeys:@[@"tagNumber", @"ukNumber", @"age", @"breed", @"comments"] columnHeaders:@[@"Tag Number", @"UK Number", @"Age", @"Breed",  @"Comments"]];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [loadingBar stop];
                    [loadingBar dismiss];
                    NSSavePanel *panel = [NSSavePanel savePanel];
                    [panel beginSheetModalForWindow:[[NSApplication sharedApplication] mainWindow] completionHandler:^(NSInteger result) {

                    }]; 
                });
            });
        }

这是一个已知错误还是在我的代码中?如果这是一个已知的错误,我可以绕过它。

  • 编辑:这是我在解决它之前的问题(感谢@serren的修复):

首先取消选中主窗口控制器中的Is Initial Controller(您的应用程序现在不会自动启动主窗口)。

然后:

AppDelegate.h

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>
// Add strong reference to the root window controller
@property (strong) NSWindowController *rootController;


@end

最后在AppDelegate.m实现applicationDidFinishLaunching:就像这样(记得设置你的初始控制器标识符,这里我的是“HomeView”):

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
    // Show main window (to avoid powerbox bug)...
    NSStoryboard *sb = [NSStoryboard storyboardWithName:@"Main" bundle:nil];
    rootController = [sb instantiateControllerWithIdentifier:@"HomeView"];
    [rootController showWindow:self];

    // Other custom setup for your App...
}

此过程意味着NSApplication的{​​{1}}属性将自动设置为mainWindow。因此,如果您想随时获取主窗口,仍然可以致电rootController.window [[NSApplication sharedApplication] mainWindow];AppDelegate单身人士都对此窗口有强烈的引用,这很重要(否则窗口将被释放,应用程序将崩溃)。

希望这有助于暂时。

3 个答案:

答案 0 :(得分:1)

简短说明:

这看起来像是一个与ArrayController有关的错误,也许是该主要任何其他类似的控制器或它继承的任何东西或IB中的绑定系统。这是一个简单的代码,详细说明了问题:https://www.dropbox.com/s/atwoc2hweh5fjk6/Bug.zip?dl=0

详细说明:

看起来SDK内部发生了一些奇怪的事情。

在我提供的示例中,我有一个使用标准Xcode 6.1模板生成的标准应用程序。该应用程序是沙盒。在应用程序委托中,我们只是测试NSSavePanel是否会在没有任何问题的情况下触发。 ViewController声明一个名为&#34; array&#34;的属性。稍后绑定到NSArrayController(参见Main.storyboard内部)。

如果在此设置中启动应用程序,您将看到NSSavePanel失败。但是,如果我们只是关闭NSArrayController绑定,对NSSavePanel的调用奇迹般地起作用。

因此,可以安全地假设这只是隐藏在最新SDK下面的一个坏错误,苹果需要修复它。

随意将示例添加到您向Apple发送的错误报告中。

<强> Woraround:

如果您禁用&#34;引发不适用的密钥&#34;数组控制器绑定中的选项可以让应用程序再次运行而不会关闭绑定本身。这可能意味着在设置连接到XPC服务的沙箱之前会引发异常,从而导致应用程序出现异常。

正确的解决方案是让苹果将XPC连接初始化代码放置在防止奇怪错误和异常的地方,从而确保它始终有效。

<强>更新

基于serenn建议我使用以下代码使我的应用程序按预期运行:

    let sb = NSStoryboard(name: "Main", bundle: nil)!

    // ---

    rootWindowController = sb.instantiateControllerWithIdentifier("MainWindowController") as? NSWindowController

    // ---

    rootWindowController?.showWindow(self)

在我的测试中,我发现rootWindowController?.showWindow(self)可以更好地显示窗口而不是makeKeyAndOrderFront,因为否则segue无法正确连接(弹出窗口等)。这种方法对我有用。

答案 1 :(得分:1)

不幸的是,上面的答案与我的场景无关,因为创建NSSavePanel的屏幕上没有ArrayControllers。

对原始问题的评论之一指出了我正确的方向,即摆脱自定义WindowController子类。当我这样做时,小组看起来很好。但是,由于这不是一个很好的解决方案(如果你真的想保留你的自定义类),我一直在挖掘..

仅供参考,我正在使用NSStoryboards并为10.10构建应用程序。

当我(暂时)在我的主窗口上取消选中“Restorable”时,我发现了一些奇怪的行为 - 每次出现保存面板时,我的应用程序的新主窗口都会出现。这让我相信我的app委托与所显示的主窗口有很大的脱节 - 特别是现在,故事板有一个单独的Application Scene和WindowController。

我做了什么:

  1. 选择我的主窗口控制器和UNCHECK“Is Initial Controller”(即没有为故事板设置初始控制器)
  2. 在我的app委托中,在applicationDidFinishLaunching:中,我手动创建了故事板并使用instantiateControllerWithIdentifier:
  3. 加载了窗口控制器
  4. 我将self.window设置为创建的windowController.window属性
  5. 我做了自己。关键和订单前面(使用makeKeyAndOrderFront:
  6. 应用程序启动,像以前一样加载窗口,但现在保存面板显示正常。它也适用于自定义windowController子类。

    最后,作为奖励,我在使用applicationShouldTerminateAfterLastWindowClosed(设置为NO)时终于有了正确的行为

答案 2 :(得分:0)

根据App Sandbox Design Guide,您应该创建自己的NSDocument子类。 NSDocument有自己的方法来显示保存对话框:

  

NSDocument类自动与Powerbox一起使用。如果用户使用Finder移动文档,NSDocument还支持将文档保留在沙箱中。

     

请记住,当您的应用程序是沙盒时,NSOpenPanel和NSSavePanel类的继承路径会有所不同。请参阅使用App Sandbox打开和保存对话框行为。

     

由于此运行时差异,NSOpenPanel或NSSavePanel对象使用App Sandbox继承较少的方法。如果您尝试将消息发送到NSOpenPanel或NSSavePanel对象,并且该方法在NSPanel,NSWindow或NSResponder类中定义,则系统会引发异常。 Xcode编译器不会发出警告或错误来提醒您此运行时行为。