1

我在沙盒应用程序中使用 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) {

                    }]; 
                });
            });
        }

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

  • 编辑:这就是我解决它的方式,直到 Apple 修复它(感谢@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'mainWindow属性将rootController.window自动设置为 。因此,如果您想随时获取主窗口,您仍然可以调用[[NSApplication sharedApplication] mainWindow];Also theAppDelegateNSApplication单例都对该窗口有很强的引用,这很重要(否则窗口将被释放,应用程序将崩溃)。

希望这暂时有所帮助。

4

3 回答 3

1

简短的介绍:

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

详细描述:

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

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

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

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

随时将示例添加到您向 Apple 提交的错误报告中。

解决方法:

看起来如果您在阵列控制器绑定中禁用“Raises For Not Applicable Keys”选项,您可以让应用程序再次工作而无需关闭绑定本身。这可能意味着在设置连接到 XPC 服务的沙箱之前引发了异常,从而使应用程序行为异常。

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

更新

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

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

    // ---

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

    // ---

    rootWindowController?.showWindow(self)

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

于 2014-11-09T19:34:30.307 回答
1

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

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

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

当我(暂时)在我的主窗口上取消选中“可恢复”时,我注意到一些奇怪的行为——每次保存面板出现时,我的应用程序的新主窗口就会出现。这让我相信我的应用程序委托与正在显示的主窗口有很大的脱节——尤其是现在情节提要具有单独的应用程序场景和 WindowController。

我做了什么:

  1. 选择我的主窗口控制器并取消选中“是初始控制器”(即没有为情节提要设置初始控制器)
  2. 在我的应用程序委托中applicationDidFinishLaunching:,我手动创建了故事板并使用instantiateControllerWithIdentifier:
  3. 我将 设置self.window为创建的 windowController.window 属性
  4. 我将 self.window 设置为键和命令前面(使用makeKeyAndOrderFront:

应用程序启动,像以前一样加载窗口,但现在保存面板看起来很好。它也适用于自定义 windowController 子类。

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

于 2014-12-03T21:27:59.203 回答
0

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

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

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

由于这种运行时差异,NSOpenPanel 或 NSSavePanel 对象继承的应用沙盒方法更少。如果您尝试向 NSOpenPanel 或 NSSavePanel 对象发送消息,并且该方法在 NSPanel、NSWindow 或 NSResponder 类中定义,系统会引发异常。Xcode 编译器不会发出警告或错误来提醒您注意此运行时行为。

于 2014-12-10T16:48:52.787 回答