NSSavePanel crashes on runModal()

Components:

macOS 11.6, iMac (Retina 5K, 27-inch, Late 2014), Xcode: Version 13.0 (13A233) Capabilities: User selected & Download folder files Read/Write Language Swift 5

Small App fragment

========= BEGIN =========

import Cocoa

@main

class AppDelegate: NSObject, NSApplicationDelegate, NSComboBoxDelegate, NSOpenSavePanelDelegate {

    let dialog = NSSavePanel()

    @IBOutlet var window: NSWindow!

    @IBOutlet weak var selectOutFileLabelOutlet: NSTextField!

    @IBOutlet weak var selectFileCBOutlet : NSComboBox!

    @IBOutlet weak var ouputFileNameOutlet: NSTextField!

    @IBOutlet weak var browse4FileOutlet  : NSButton!

    @IBOutlet weak var progressBarOutlet  : NSProgressIndicator!

    @IBOutlet weak var convertButtonOutlet: NSButton!

  @IBAction func convertButtonClicked(_ sender: Any) {

   // STUB

    }

    @IBAction func browseButtonClicked(_ sender: Any) {

        dialog.title = "Choose output file"

        dialog.showsResizeIndicator = true

        dialog.showsHiddenFiles = true

        dialog.canCreateDirectories    = true

        dialog.allowedFileTypes = [".ear", ".mer", ".ven", ".mar", ".jup", ".sat", ".ura", ".nep", ".plu"]

        dialog.allowsOtherFileTypes = true

        dialog.treatsFilePackagesAsDirectories = true

    let answer = dialog.runModal() // ERROR

        if answer ==  NSApplication.ModalResponse.OK {

            let results = dialog.url

            // Do whatever you need with every selected file

        print ( results!.path )

        } else {

            print ( "User clicked on 'Cancel'" )

            return

        }

    }

    var sourceFileName     : String = ""

    var targetFileName     : String = ""

    let resourcePathPrefix : String = "(Bundle.main.resourcePath!)/VSOP87-Files/"

    var outputFilePath     : String = ""

    func applicationDidFinishLaunching(_ aNotification: Notification) {

        // Insert code here to initialize your application

        dialog.delegate = self

        selectFileCBOutlet.delegate = self

        setupComboBox()

    }

}

====================

When the action: browseButtonClicked(_ sender: Any) is called all the properties of the "dialog" are set then after quite a wait (4 seconds or so) the following error is issued:

=== ERROR ==========

`2021-10-03 15:24:17.110702-0700 ConvertVSOPToDataFile[4887:105883] -[NSSavePanel beginServicePanel]_block_invoke : Could not advance an Open/Save panel to run phase due to error: Error Domain=com.apple.ViewBridge Code=16 "(null)" UserInfo={com.apple.ViewBridge.error.hint=advance to run phase, com.apple.ViewBridge.error.description=NSViewBridgeInvalidError}

2021-10-03 15:24:17.114075-0700 ConvertVSOPToDataFile[4887:105883] -[NSSavePanel beginServicePanel] : an exception occurred during attempt to advance an Open/Save panel to run phase!

2021-10-03 15:24:17.116188-0700 ConvertVSOPToDataFile[4887:105883] -[NSSavePanel runModal] caught non-fatal NSObjectNotAvailableException 'The operation couldn’t be completed. (com.apple.ViewBridge error 16.)' with user dictionary {

    error = "Error Domain=com.apple.ViewBridge Code=16 "(null)" UserInfo={com.apple.ViewBridge.error.hint=advance to run phase, com.apple.ViewBridge.error.description=NSViewBridgeInvalidError}";

} and backtrace (

0   CoreFoundation                      0x00007fff205601db __exceptionPreprocess + 242

1   libobjc.A.dylib                     0x00007fff20299d92 objc_exception_throw + 48

2   AppKit                              0x00007fff237148ab -[NSSavePanel beginServicePanel] + 717

3   AppKit                              0x00007fff23715044 -[NSSavePanel runModal] + 98

4   ConvertVSOPToDataFile               0x000000010334cea1 $s21ConvertVSOPToDataFile11AppDelegateC19browseButtonClickedyyypF + 1313

5   ConvertVSOPToDataFile               0x000000010334d681 $s21ConvertVSOPToDataFile11AppDelegateC19browseButtonClickedyyypFTo + 65

6   AppKit                              0x00007fff22f0e2bb -[NSApplication(NSResponder) sendAction:to:from:] + 288

7   AppKit                              0x00007fff22f0e15f -[NSControl sendAction:to:] + 86

8   AppKit                              0x00007fff22f0e091 __26-[NSCell _sendActionFrom:]_block_invoke + 131

9   AppKit                              0x00007fff22f0df98 -[NSCell _sendActionFrom:] + 171

10  AppKit                              0x00007fff22f0dede -[NSButtonCell _sendActionFrom:] + 96

11  AppKit                              0x00007fff22f0afc7 NSControlTrackMouse + 1820

12  AppKit                              0x00007fff22f0a883 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 130

13  AppKit                              0x00007fff22f0a74a -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 697

14  AppKit                              0x00007fff22f09a72 -[NSControl mouseDown:] + 722

15  AppKit                              0x00007fff22f07e5e -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 4961

16  AppKit                              0x00007fff22e77648 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2594

17  AppKit                              0x00007fff22e76a06 -[NSWindow(NSEventRouting) sendEvent:] + 347

18  AppKit                              0x00007fff22e74e14 -[NSApplication(NSEvent) sendEvent:] + 352

19  AppKit                              0x00007fff2314dbe1 -[NSApplication _handleEvent:] + 65

20  AppKit                              0x00007fff22cddc8e -[NSApplication run] + 623

21  AppKit                              0x00007fff22cb1e6c NSApplicationMain + 816

22  ConvertVSOPToDataFile               0x0000000103350064 $sSo21NSApplicationDelegateP6AppKitE4mainyyFZ + 36

23  ConvertVSOPToDataFile               0x0000000103350037 $s21ConvertVSOPToDataFile11AppDelegateC5$mainyyFZ + 39

24  ConvertVSOPToDataFile               0x0000000103350208 main + 24

25  libdyld.dylib                       0x00007fff20409f3d start + 1

26  ???                                 0x0000000000000003 0x0 + 3

)

==============` END =============

Failure is consistent as is the error output.

Any ideas would be appreciated!

TIA

ClarkW

Replies

I use NSPanel differently, not as a basic Dialog:

Line 26, I would change for:

     dialog.begin() { (result) -> Void in
     if result == NSApplication.ModalResponse.OK {
          let results = dialog.url
          // Do whatever you need with every selected file
          print ( results!.path )
     } else {
          print ( "User clicked on 'Cancel'" )
          return
     }
}

For reference:

1. import Cocoa
2. @main
3. class AppDelegate: NSObject, NSApplicationDelegate, NSComboBoxDelegate, NSOpenSavePanelDelegate {
4. 
5.      let dialog = NSSavePanel()
6.      @IBOutlet var window: NSWindow!
7.      @IBOutlet weak var selectOutFileLabelOutlet: NSTextField!
8.      @IBOutlet weak var selectFileCBOutlet : NSComboBox!
9.      @IBOutlet weak var ouputFileNameOutlet: NSTextField!
10.     @IBOutlet weak var browse4FileOutlet  : NSButton!
11.     @IBOutlet weak var progressBarOutlet  : NSProgressIndicator!
12.     @IBOutlet weak var convertButtonOutlet: NSButton!
13. 
14.      @IBAction func convertButtonClicked(_ sender: Any) {
15.    // STUB
16.     }
17.      
18.      @IBAction func browseButtonClicked(_ sender: Any) {
19.           dialog.title = "Choose output file"
20.           dialog.showsResizeIndicator = true
21.           dialog.showsHiddenFiles = true
22.           dialog.canCreateDirectories    = true
23.           dialog.allowedFileTypes = [".ear", ".mer", ".ven", ".mar", ".jup", ".sat", ".ura", ".nep", ".plu"]
24.           dialog.allowsOtherFileTypes = true
25.           dialog.treatsFilePackagesAsDirectories = true
26.           let answer = dialog.runModal() // ERROR
27.           if answer ==  NSApplication.ModalResponse.OK {
28.                let results = dialog.url
29.                // Do whatever you need with every selected file
30.                print ( results!.path )
31.           } else {
32.                print ( "User clicked on 'Cancel'" )
33.                return
34.           }
35.      }
36.      
37.     var sourceFileName     : String = ""
38.     var targetFileName     : String = ""
39.     let resourcePathPrefix : String = "(Bundle.main.resourcePath!)/VSOP87-Files/"
40.     var outputFilePath     : String = ""
41.      
42.     func applicationDidFinishLaunching(_ aNotification: Notification) {
43.         // Insert code here to initialize your application
44.         dialog.delegate = self
45.         selectFileCBOutlet.delegate = self
46.         setupComboBox()
47.     }
48. }

  • Better response but still ultimately crashes with same error: I do however get a notification indicting: "The save file operation failed." "The save file operation failed to connect to the open and save panel service."

    This is followed in the debugger console output with exactly the same output as shown in previous message. However the behavior is slightly different. There is a pause before the rainbow wheel indicates busy and as noted I do get the notification.

    I do appreciate the assistance and am grateful for any additional information or actions you could suggest. This is very strange to me. Oh I tried rewriting this in Objective-c and get a similar runtime failure.

    Very strange. ClsrkW

Add a Comment

First up, some minor things:

  • You’re creating a single instance of NSSavePanel. That’s supported but weird. I recommend that you create an instance each time you run the panel. So, remove the dialog property and instead start your browseButtonClicked(_:) method with:

    @IBAction func browseButtonClicked(_ sender: Any) {
        let dialog = NSSavePanel()
        …
    }
    
  • When you post code snippets, please format that as code by clicking the Code Block button (or adding triple backquote delimiters manually). That’ll make it much easier to see what’s going on.

With regards your main issue, I created a new project from the macOS > App template and added your code to it. I then cut your code down so that it’d build and run. Here’s what I ended up with:

import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {
    
    @IBOutlet var window: NSWindow!
    
    @IBAction func browseButtonClicked(_ sender: Any) {
        let dialog = NSSavePanel()
        dialog.title = "Choose output file"
        dialog.showsResizeIndicator = true
        dialog.showsHiddenFiles = true
        dialog.canCreateDirectories    = true
        dialog.allowedFileTypes = [".ear", ".mer", ".ven", ".mar", ".jup", ".sat", ".ura", ".nep", ".plu"]
        dialog.allowsOtherFileTypes = true
        dialog.treatsFilePackagesAsDirectories = true
        let answer = dialog.runModal() // ERROR
        if answer ==  NSApplication.ModalResponse.OK {
            let results = dialog.url
            // Do whatever you need with every selected file
            print ( results!.path )
        } else {
            print ( "User clicked on 'Cancel'" )
            return
        }
    }
}

This works as expected.

I recommend that you repeat this experiment to confirm that there’s not some environmental problem causing this issue. That’ll also give you a known working baseline. From there you can add code to your baseline, or temporarily remove code from your main app, until you can work out what cause them to behave differently.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"