When this URL extension is run as a panel it fails to return a URL, seemingly bypassing the completion:
func saveAs() -> URL? {
let savePanel = NSSavePanel()
var saveAsURL : URL? = nil
savePanel.canCreateDirectories = true
savePanel.nameFieldStringValue = self.lastPathComponent
savePanel.directoryURL = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first!
if let keyWindow = NSApp.keyWindow {
savePanel.beginSheetModal(for: keyWindow, completionHandler: { result in
/*if result == .OK {*/ saveAsURL = savePanel.url //}
})
}
else
{
NSApp.activate(ignoringOtherApps: true)
if savePanel.runModal() == .OK {
saveAsURL = savePanel.url
}
}
Swift.print("saveAsURL => \(saveAsURL.debugDescription)")
return saveAsURL
}
but run as standalone window it works fine. There is another related answer here but here the usage is different: i.e.
guard let saveAsURL = URL.init(string: "download.dmg").saveAs() else { return }
where I presume a user cancel would infer the processing should end.
When you say
.runModalyour code does a very, very odd thing: it stops and waits for the user to deal with the modal dialog (also known as blocking). That goes back to the extremely early days of OS X / Cocoa, and is an anomaly in behavior. So the result is that by the time we get to the end of the method and yourSwift.printandreturn, we are back from the modal dialog and we have the value from it.But, as I say, that's totally weird. (In fact, I'm not sure I can think of any other Cocoa call that acts like that.) The
.beginSheetModalcall behaves normally, i.e. after the call your code goes right on and gets to the end with theprintandreturnbefore the modal sheet even has a chance to appear. What happens within the modal sheet then happens asynchronously with respect the calling code here — i.e. later. Thus you cannot return any value from the dialog because you'd need a time machine to look into the future. That is the standard pattern for this sort of thing.