我正在 SwiftUI 中编写一个 Mac 应用程序,希望显示实时更新的文档和文件夹列表,并且能够编辑文件。
首先,用户使用“打开文件”对话框选择任何文件夹,然后我将 URL 保存到 UserDefaults 中,并在应用程序启动时尝试读取文件和文件夹列表。
假设我有一个有效的 URL,那么我会执行以下操作:
// Open the folder referenced by URL for monitoring only.
monitoredFolderFileDescriptor = open(url.path, O_EVTONLY)
// Define a dispatch source monitoring the folder for additions, deletions, and renamings.
folderMonitorSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: monitoredFolderFileDescriptor, eventMask: .write, queue: folderMonitorQueue)
当我调用
DispatchSource.makeFileSystemObjectSource
并出现 EXC_BREAKPOINT
异常时,应用程序崩溃。
FileManager.default.isReadableFile(atPath: url.path)
返回 false,告诉我我没有访问此文件夹的权限。
URL路径是/Users/username/Documents/Folder
我已将
NSDocumentsFolderUsageDescription
添加到信息列表中。
目前尚不清楚如何以编程方式请求许可。 理论上,我的 URL 可以指向用户在“打开”对话框中选择的文件系统上的任何文件夹。目前尚不清楚仅在必要时请求许可的最佳做法是什么。我应该解析“文档”或“下载”字符串的 URL 吗? 我也看过这个 WWDC 视频。
感谢您的阅读,这是我想要展示的示例。
就像@vadian 所说,这需要安全范围书签。如果您用户从
NSOpenPanel
选择文件夹,则不需要权限对话框。 这个答案对我帮助很大。
我创建了新的
NSOpenPanel
,它给了我 URL?
,我将此 URL 传递给下面的 saveAccess()
函数:
let bookmarksPath = "bookmarksPath"
var bookmarks: [URL: Data] = [:]
func saveAccess(url: URL) {
do {
let data = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
bookmarks[url] = data
NSKeyedArchiver.archiveRootObject(bookmarks, toFile: bookmarksPath)
} catch {
print(error)
}
}
保存书签后,您可以在应用程序启动时访问。
func getAccess() {
guard let bookmarks = NSKeyedUnarchiver.unarchiveObject(withFile: bookmarksPath) as? [URL: Data] else {
print("Nothing here")
return
}
guard let fileURL = bookmarks.first?.key else {
print("No bookmarks found")
return
}
guard let data = bookmarks.first?.value else {
print("No data found")
return
}
var isStale = false
do {
let newURL = try URL(resolvingBookmarkData: data, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
newURL.startAccessingSecurityScopedResource()
print("Start access")
} catch {
print(error)
return
}
}
代码很粗糙,但我希望它可以帮助别人。获取
newURL
后,即可打印文件夹内容。
let files = try FileManager.default.contentsOfDirectory(at: newURL, includingPropertiesForKeys: [.localizedNameKey, .creationDateKey], options: .skipsHiddenFiles)
完成后别忘了打电话给
.stopAccessingSecurityScopedResource()
。