'NSOpenPanel, NSSavePanel runModal dismisses immediately with cancel, but only on M1 running 11.4
I have one user who reports that the Open and Save panels have been "auto dismissing". ie the Open Panel dialog appears then immediately dismisses itself, taking the "cancel" path through the code
The file Open menu item is the standard firstResponder openDocument IBAction in the Storyboard
There is an IBAction openDocument routine in the AppDelegate which posts a notification which is observed by the main ViewController and which creates the NSOpenPanel and displays it with RunModal
class AppDelegate: NSObject, NSApplicationDelegate {
// standard AppDelegate routines omitted for brevity
@IBAction func openDocument(_ sender: NSMenuItem) {
let nc = NotificationCenter.default
nc.post(Notification(name: Notification.Name("documentOpenRequested"), object: object))
}
}
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(doOpenDocument), name: Notification.Name("documentOpenRequested"), object: nil)
}
@objc func doOpenDocument(_ notification: Notification) {
print ("doOpenDocument called on MainThread: \(Thread.current.isMainThread)")
var URLToOpen: URL?
if let selectedURL = notification.object as? URL {
URLToOpen = selectedURL
} else {
let openPanel = NSOpenPanel();
openPanel.allowsMultipleSelection = false;
openPanel.canChooseDirectories = false;
openPanel.canCreateDirectories = false;
openPanel.canChooseFiles = true;
openPanel.allowedFileTypes = ["sdf", "json", "txt"]
openPanel.allowsOtherFileTypes = true
let i = openPanel.runModal();
if i.rawValue == NSApplication.ModalResponse.OK.rawValue {
if let myURL = openPanel.url {
URLToOpen = myURL
NSDocumentController.shared.noteNewRecentDocumentURL(myURL)
}
} else {
print ("RunModal exited with response not OK")
}
}
guard let theURL = URLToOpen else {
// URL was bad or user aborted open request, either way just bail
return
}
}
The expected behaviour is that the RunModal displays the OpenDialog and waits for the user to select file and hit OK or Cancel, and that is what I get on my machine.
However on this one user's machine (MacBook Pro 13" M1 2020 running 11.4 ), the RunModal immediately exits taking the path which would print "RunModal exited with response not OK". Therefore the user is unable to choose a file
I did read some things which suggested doing an NSOpenPanel on other than the main queue could cause crashing. Willeke's reference suggests that notifications in this case would be posted on the main queue. I updated the sample to print whether the queue was the main queue and on my system it prints
doOpenDocument called on MainThread: true
So sticking the NSOpenPanel in a
DispatchQueue.main.async {
let openPanel = ...
}
would not seem to solve the problem.
I don't have access to the specific machine which can replicate the error, making further debugging difficult. The "auto cancel" behaviour appears limited to this one user's machine but the config is common enough that I suspect I would be getting other reports even if it was limited to that specific config with M1 chip etc
Can anyone replicate this behaviour on this or other machines or run into any other reason for this "auto cancel" happening? (system setting, virus checker, etc)?
(Question updated to give expected behaviour and behaviour occurring, further debugging info, code info request by others and suggestions)
Solution 1:[1]
I can replicate this behavior on M1 iMac with OS X 12.3.1 & Xcode 13.3.1 in SwiftUI based utility for MacOS X 12.3.
The issue has not yet been corrected. Other developers have suggested I switch to FileDocument & DocumentGroup protocols instead. No-one can explain this unusual behavior of NSOpenPanel immediately cancelling when called within a SwiftUI View.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |