URL security bookmark with subdirectories

I persist user selected directory URL to UserDefaults and resolve the bookmark on view load:

override func viewDidLoad() {
        super.viewDidLoad()

        if let bookmarkData = Preferences.instance.lastDirBookmark {
            do {
                var isStale = false
                self.lastDirURL = try URL(resolvingBookmarkData: bookmarkData,
                                     options: .withSecurityScope,
                                     relativeTo: nil,
                                     bookmarkDataIsStale: &isStale)
                if isStale {
                    Preferences.instance.lastDirBookmark = try self.createBookmark(self.lastDirURL!)
                }
                self.directoryTextField.stringValue = self.lastDirURL!.path
            } catch {
                NSAlert.errorAlert(error, for: self.view.window!)
            }
        }
    }

    @IBAction func locate_click(_ sender: Any) {
        let openPanel = NSOpenPanel()
        openPanel.canChooseDirectories = true
        openPanel.canChooseFiles = false
        openPanel.allowsMultipleSelection = false
        if openPanel.runModal() == .OK {
            if let url = openPanel.url {
                self.directoryTextField.stringValue = url.path
                self.lastDirURL = url
                do {
                    Preferences.instance.lastDirBookmark = try self.createBookmark(url)
                    parseFiles()
                } catch {
                    NSAlert.errorAlert(error, for: self.view.window!)
                }
            }
        }
    }

    private func parseFiles() {
        if let url = self.lastDirURL {
                if url.startAccessingSecurityScopedResource() {
                self.startParseFiles()
                url.stopAccessingSecurityScopedResource()
            }
        }
    }

My app is correctly sandboxed and com.apple.security.files.user-selected.read-write is true.


The code works well for the saved path only. If I try to write files to subdirectories, access will be denied. The subdirectories are dynamic in nature, so my questions is - how to solve this problem without saving too many bookmarks?

Answered by imneo in 330063022

Thanks for your reply. I found out the reason myself. It seems I misundertood how self.presentAsSheet works:

if url.startAccessingSecurityScopedResource() {
    self.presentAsSheet(translationVC)
    url.stopAccessingSecurityScopedResource()
}

I thought url.stopAccessingSecurityScopedResource() would only get executed after the sheet is closed. Now I moved the code into the presented VC's completion handler (custom implementation):

translationVC.completionHandler = {(error) in
                    OperationQueue.main.addOperation {
                        url.stopAccessingSecurityScopedResource()
                        self.translationTable.reloadData()
                    }
                }

A security scoped bookmark to a folder should let you read, write and create subfolders, and files inside subfolders. If that weren't so, it wouldn't be possible to create a document package.


Maybe you can show how you form the URLs you use to create subdirectories, and the files you write inside them?

Accepted Answer

Thanks for your reply. I found out the reason myself. It seems I misundertood how self.presentAsSheet works:

if url.startAccessingSecurityScopedResource() {
    self.presentAsSheet(translationVC)
    url.stopAccessingSecurityScopedResource()
}

I thought url.stopAccessingSecurityScopedResource() would only get executed after the sheet is closed. Now I moved the code into the presented VC's completion handler (custom implementation):

translationVC.completionHandler = {(error) in
                    OperationQueue.main.addOperation {
                        url.stopAccessingSecurityScopedResource()
                        self.translationTable.reloadData()
                    }
                }
URL security bookmark with subdirectories
 
 
Q