简体   繁体   中英

NSOpenPanel sometimes does not return NSOpenPanel.urls

My app should import text files. With NSOpenPanel I can select files, and after closing the panel, it should import files one by one. This is done by sending a notification self.nextFile() for each file to an observer who manages the import.

Here is my code nippest:


    func selectFiles() {
        fileIndex = 0
        fileList  = [URL]()
        
        recordsImported = 0
        numberOfLines = 0
        let openPanel = NSOpenPanel()
        openPanel.allowsMultipleSelection = true
        openPanel.canChooseDirectories = false
        openPanel.canCreateDirectories = false
        openPanel.canChooseFiles = true
        //openPanel.allowedFileTypes = ["csv"]  // deprecated !
        openPanel.delegate = self
        openPanel.accessoryView = loadAccessoryVC!.view as NSView
        openPanel.beginSheetModal(for:(NSApplication.shared.mainWindow)!) { (response) in
            if response == .OK {
                self.fileList = openPanel.urls
                self.nextFile(notification: Notification(name:Notification.Name("next file")))
            }
            
            openPanel.close()
        }

Most of the time it works fine, but sometimes the openPanel.urls is empty - especially if my list is more than 20 files. It looks like the open panel is not yet finished before self.nextFile() is called.

  • Xcode version: 14.01
  • deployment target: MAC OS 10.15

Any idea how to sync it? Could @escaping statement in the closure help?

I found the root cause: It is not very easy to describe.
It was a side effect of initialising objects at the wrong place in my code.
The app is a Core Data app, and when I open more than one document, I did not take care to give each document its own importing object and NSManagedObjectContext. When it comes to the notification to import a (next) file, it was calling for both documents. But only one had a list of files; the second was empty

Lesson learned: Initiate objects that belong to a document in NSDocument and not globally ( as in Appdelegate or NSApp..) Use make WindowController as described in Apple´s documentation. :

override func makeWindowControllers() {
    // Returns the Storyboard that contains your Document window.
    let storyboard = NSStoryboard(name: "Main", bundle: nil)
    if let windowController = storyboard.instantiateController(withIdentifier: "Document Window Controller") as? NSWindowController {
        addWindowController(windowController)
        

        if let contentVC = windowController.contentViewController as? MyViewManager {
            // NSPersistentdocument creates the managedObjectComtext itself:
            contentVC.representedObject = self.managedObjectContext
            contentViewController = contentVC                
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM