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?
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()
}
}