NSSavePanel crash in sandbox app OS X 10.10

≯℡__Kan透↙ 提交于 2019-12-11 06:30:11

问题


I'm using the NSSavePanel in OS X 10.10 in a sandboxed app to let the user choose the save location of a file (pretty standard), however the app crashes when i call:

NSSavePanel *panel = [NSSavePanel savePanel];

I get this in the debugger:

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

This is my code in full:

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) {

                    }]; 
                });
            });
        }

Is this a known bug or is it something in my code? If it's a known bug can I get round it.

  • EDIT: This is how I'm getting around it until Apple fix it (thank's to @serren for the fix):

First uncheck the Is Initial Controller in your primary window controller (your App won't automatically launch the main window now).

Then:

In the AppDelegate.h:

#import <Cocoa/Cocoa.h>

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


@end

Finally in AppDelegate.m implement applicationDidFinishLaunching: like so (remember to set your initial controller identifier, here mine is "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...
}

This process will mean that the NSApplication's mainWindow property will be set to the rootController.window automatically. So if you want to get your main window at any time you can still call [[NSApplication sharedApplication] mainWindow]; Also the AppDelegate and the NSApplication singleton both have a strong reference to this window which is important (otherwise the window will be released and the App will crash).

Hope this helps for the time being.


回答1:


Unfortunately the answer above had nothing to do with my scenario, as there were no ArrayControllers present on the screen creating the NSSavePanel.

One of the comments to the original question pointed me in the right direction though, which was to get rid of the custom WindowController subclass. When I did that, the panel appeared just fine. However, since that's not a great solution (in case you really want to keep your custom class), I kept digging..

FYI, I am using NSStoryboards and building the app for 10.10.

I noticed some weird behavior when I (temporarily) unchecked "Restorable" on my main window--every time the save panel appeared, a new main window of my app appeared. That led me to believe that my app delegate had a major disconnect with the primary window being shown--especially now with storyboards having a separate Application Scene and WindowController.

What I did:

  1. Select my primary window controller and UNCHECK "Is Initial Controller" (i.e. there is no initial controller set for the storyboard)
  2. In my app delegate, in applicationDidFinishLaunching:, I manually created the storyboard and loaded the window controller using instantiateControllerWithIdentifier:
  3. I set the self.window to the created windowController.window property
  4. I made self.window the key and order front (using makeKeyAndOrderFront:)

The app launches, loads the window as before, but now the save panel appears just fine. It also works with a custom windowController subclass.

Finally, as a bonus, I finally have the proper behavior when using applicationShouldTerminateAfterLastWindowClosed (being set to NO)




回答2:


Short Description:

This look like a bug somehow related to ArrayController and perhaps any other similar controller for that mater or whatever it inherits or the bindings system in IB. Here is a simple code which demonstrates the problem in detail: https://www.dropbox.com/s/atwoc2hweh5fjk6/Bug.zip?dl=0

Long Description:

It looks like that something weird is going on inside the SDK.

In the example that I have provided I have a standard application generated with a standard Xcode 6.1 template. The application is sandboxed. Inside the application delegate we simply test if the NSSavePanel will fire without any problems. The ViewController declares a property called "array" which is later bound to an NSArrayController (see inside Main.storyboard).

If you launch the application in this setup you will see that the NSSavePanel fails. However, if we simply turn off the NSArrayController binding, the call to NSSavePanel miraculously work.

Therefore, it is safe to assume that this is nothing but a bad bug hidden underneath the latest SDK, which apple needs to fix.

Feel free to add the sample to your bug report to Apple.

Woraround:

It looks like if you disable the "Raises For Not Applicable Keys" option inside the array controller binding you get the application to work again without turning off the binding itself. This probably means that an exception is raised before setting up the sandbox connecting to the XPC service therefore making the application misbehave.

The proper fix will be for apple to put the XPC connection initialization code somewhere where it is guarded from weird errors and exceptions therefore ensuring that it is always working.

UPDATE

Based on serenn suggestion I use the following code to make my application behave as expected:

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

    // ---

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

    // ---

    rootWindowController?.showWindow(self)

In my tests I find that rootWindowController?.showWindow(self) works better to show the window instead of makeKeyAndOrderFront because otherwise the segues don't get properly connected (popups, etc). This method works for me.




回答3:


According to the App Sandbox Design Guide you should create your own subclass of NSDocument. NSDocument has its own method for presenting the save dialog:

The NSDocument class automatically works with Powerbox. NSDocument also provides support for keeping documents within your sandbox if the user moves them using the Finder.

Remember that the inheritance path of the NSOpenPanel and NSSavePanel classes is different when your app is sandboxed. See Open and Save Dialog Behavior with App Sandbox.

Because of this runtime difference, an NSOpenPanel or NSSavePanel object inherits fewer methods with App Sandbox. If you attempt to send a message to an NSOpenPanel or NSSavePanel object, and that method is defined in the NSPanel, NSWindow, or NSResponder classes, the system raises an exception. The Xcode compiler does not issue a warning or error to alert you to this runtime behavior.



来源:https://stackoverflow.com/questions/26366711/nssavepanel-crash-in-sandbox-app-os-x-10-10

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!