1

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.

Rob Sanders
  • 5,197
  • 3
  • 31
  • 58
  • One of my users is getting that error too. With this line of code: NSOpenPanel *openPanel = [NSOpenPanel openPanel]; Did you found out what it was ? – the Reverend Oct 27 '14 at 04:00
  • Not yet but I have now filed a bug report with apple. I think it's a problem with their NSXPCService that connects a sandboxed app to the user's files. – Rob Sanders Oct 28 '14 at 10:14
  • If you have the bug number I will add it to mine. Thanks! – the Reverend Oct 28 '14 at 18:45
  • 18679387 is the bug number. – Rob Sanders Oct 28 '14 at 20:18
  • Appended the bug number to mine. Thanks. – the Reverend Oct 29 '14 at 00:44
  • Do you have any updates on this? I am experiencing the exact same problem it looks like it maybe a combination of a few things. If I create a basic application and invoke NSSavePanel then it works but in my code it doesn't. Somehow, something interrupts the connection. – Pass Nov 09 '14 at 17:25
  • It's a problem with an NSXPCService that apple use to connect a sandboxed app to the file system as far as I'm aware. I got a reply from the apple technical support team and they told me that it was a problem with my code signing. I have checked my project configurations and I can't see anything wrong with them which is what I have told apple. I think the best thing to do is inundate them with bug reports until they take the issue seriously. – Rob Sanders Nov 09 '14 at 17:57
  • It sort of occurs in a very bizarre way. I believe the issue is not related to code-signing but something much deeper. Are you using storyboards? – Pass Nov 09 '14 at 18:49
  • 1
    Just to clarify, I still don't know what the problem is but I know that in my particular case (I am using storyboards) if I don't use a custom NSWindowController class, it all works out fine. As soon as I add a custom NSWindowController subclass then it fails. It worth nothing that in a very simple project that pattern cannot be replicated. This is why I find the bug very, very strange. – Pass Nov 09 '14 at 18:58
  • Interesting. I am subclassing NSWindowController and using storyboards. – Rob Sanders Nov 10 '14 at 09:55
  • Has anyone get anything new on this? – Rob Sanders Nov 29 '14 at 14:58
  • I wouldn't go as far as that, I think Apple are release driven in order to please the masses and often end up running out of time to smooth out the bugs. In terms of a fix use @serren's excellent work around. – Rob Sanders Jan 19 '15 at 08:59
  • 1
    that is not working for me. Regarding to Apple, one thing is to have some bugs that were hard do catch, the other is having bugs that were caught during the beta phase, that covers essential things that have to work, like opening and saving files, and release the OS without fixing them. This is what is called half cooked and there is only one situation when you start to deliver half cooked stuff, when you are doing too much and running. – Duck Feb 12 '15 at 04:13
  • I'll edit my post to show exactly how I fixed it. Although it's almost exactly identical to @serren's fix. – Rob Sanders Feb 12 '15 at 11:15

3 Answers3

1

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.

Pass
  • 1,501
  • 4
  • 21
  • 39
  • Oh, and do let us know if Apple is going to fix it :) – Pass Nov 09 '14 at 19:35
  • I will. Have you filed a bug report? – Rob Sanders Nov 10 '14 at 09:57
  • I have failed a bug 18924508. Not sure how to add to your bug but I did mention that both are related. – Pass Nov 10 '14 at 10:36
  • I'll add your bug number to my report. Cheers – Rob Sanders Nov 10 '14 at 11:10
  • Do you have any progress on your side? I have no response from Apple. – Pass Nov 15 '14 at 15:06
  • The only comment I've had from Apple was to say that they thought it was a fault of my code signing/entitlements. I told them that I had obviously checked all that before filing a bug report. Then they went quiet. I'm hoping that it'll be fixed in the next release of OS X which should be soon. – Rob Sanders Nov 15 '14 at 15:18
  • Sorry to bug you but is there any update cuz I haven't received anything yet and the latest XCode update doesn't contain any fixes? – Pass Dec 09 '14 at 11:02
  • I know. I was wondering the same. I hope Apple are actually fixing it and not ignoring it. I haven't heard anything from Apple for a while now, sorry. At the moment I'm saving all files to the downloads folder but that is less than ideal by a long way. – Rob Sanders Dec 09 '14 at 11:32
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)

serenn
  • 1,828
  • 1
  • 15
  • 11
  • Can you paste some code because I cannot make initialise the controller chain? – Pass Dec 09 '14 at 13:40
  • In my App Delegate code (which unfortunately is still written in Obj-C) -(void)applicationDidFinishLaunching:(NSNotification *)notification { NSStoryboard *storyboard = [NSStoryboard storyboardWithName:@"MainMacStoryboard" bundle:nil]; NSWindowController *controller = [storyboard instantiateControllerWithIdentifier:@"PrimaryWC"]; self.window = controller.window; [self.window makeKeyAndOrderFront:self]; } – serenn Dec 09 '14 at 17:05
  • This causes my window controller and the main window to be dealloced after about 3 seconds and the the whole app to crash. – Rob Sanders Dec 10 '14 at 18:17
  • 1
    This solution does not even works anymore on 10.10.2. On 10.10.2 the NSSavePanel works again but trying to instantiate a WindowController using `NSWindowController *controller = [storyboard instantiateControllerWithIdentifier:@"PrimaryWC"];` is not working anymore. It says that there is no object named `PrimaryWC` even if you are sure the object is there with this name. C'mon Apple! – Duck Feb 12 '15 at 04:55
  • @SpaceDog I had same issue, when I put Storyboard ID to non subclassed NSWindowController, Storyboard ID was disappearing after leaving storyboard editor. You need to subclass NSWindowController with your custom (probably empty) class so it will work. – Borzh Jul 15 '15 at 17:49
  • @RASS you need to retain your NSWindowController, assigning strong property of your AppDelegate to it. I know it sucks! – Borzh Jul 15 '15 at 17:52
  • Yea. It's working now. I'm about to embark on version 2 of this app using the latest versions of the SDK's so hopefully they've addressed this issue. – Rob Sanders Jul 15 '15 at 20:30
  • @RASS but how will you deal with the fact that your users using 10.10 and 10.10.1 will not be able to use your app? Will you limit the minimum version requirement for OS X in 10.10.2? – Duck Jul 16 '15 at 04:37
  • Yep. They'll continue receiving support but they'll only be able to upgrade if they have the latest version. It's not too much of an issue seeing as apple release OS X and iOS for free. – Rob Sanders Jul 16 '15 at 08:05
0

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.

Ian
  • 19
  • 1
  • 3
  • 1
    This bug occurs whether the call is made in `NSPanel` `NSWindow` or `NSResponder` or in another class. I have tried to call `[[NSOpenPanel openPanel] runModal]` from an class which only inherits from `NSObject` and the bug still occurs. Moreover, my app isn't document based. It's a library style application. – Rob Sanders Dec 10 '14 at 18:05