NSOpenPanel 是 macOS 框架(AppKit)中提供的一个系统级文件选择对话框类,专用于让用户选择文件或文件夹。
可以把它理解为 macOS 上的标准 “打开文件…” 弹窗。
基本用途
用于在 macOS 应用中,让用户:
1、选择一个或多个文件。
2、选择一个或多个文件夹。
3、限制选择的类型(如只选图片)。
4、获取用户选中的文件路径。
使用示例
let panel = NSOpenPanel()
panel.allowsMultipleSelection = false
panel.canChooseDirectories = false
panel.canChooseFiles = true
panel.allowedFileTypes = ["png", "jpg", "jpeg"]
if panel.runModal() == .OK {
if let url = panel.url {
print("用户选择的文件路径:\(url.path)")
}
}
常用属性
1、canChooseFiles:是否可以选择文件,true 表示可以。
panel.canChooseFiles = true
2、canChooseDirectories:是否可以选择目录,true 表示可以。
panel.canChooseDirectories = true
如果为false,则在目录视图中无法点击“打开”按钮。

3、allowsMultipleSelection:是否允许多选,true 可选多个文件或目录。
panel.allowsMultipleSelection = true
为true时,则无法按住Shift或拖动鼠标选择区域多选文件或目录。
4、urls:当用户允许多选(allowsMultipleSelection = true)时,这个数组包含所有选中的文件或目录。
for file in panel.urls {
print(file.path)
}
5、allowedFileTypes:限制选择的文件类型,[“pdf”, “txt”]。
panel.allowedFileTypes = ["pdf", "txt"]
6、directoryURL:默认打开的文件夹,FileManager.default.homeDirectoryForCurrentUser。
panel.directoryURL = FileManager.default.homeDirectoryForCurrentUser
7、title:弹窗标题,”打开文件”。
panel.title = "打开文件"
在大多数现代 macOS 系统(尤其是 macOS 11 Big Sur 及以后)中,这个标题不会在 UI 上真正显示出来。这是 Apple 系统 UI 改动的结果。
8、message:窗口上方提示文字,”请选择一个文档”。
panel.message = "请选择一个文档"

9、resolvesAliases:是否自动解析 Finder 中的“别名”文件(.alias 文件)。默认是 true。
panel.resolvesAliases = true
通常不需要改动,保持默认即可。
10、canResolveUbiquitousConflicts(macOS 10.10+):是否允许处理 iCloud 文件的版本冲突(iCloud 文件夹中可能有多个版本)。
用于打开 iCloud Drive 文件时,自动解决冲突。
panel.canResolveUbiquitousConflicts = true
11、canDownloadUbiquitousContents(macOS 10.10+):如果文件在 iCloud 中但未下载,是否允许自动下载该文件。
默认是 true,适用于从 iCloud 打开文件时。
panel.canDownloadUbiquitousContents = true
12、isAccessoryViewDisclosed(macOS 10.11+):如果设置了 accessoryView(自定义底部 UI),是否展开显示它。
默认是 false,可以设置为 true 显示。
panel.isAccessoryViewDisclosed = true
13、prompt:修改确认按钮文字(如“打开” 改成 “导入”)。
panel.prompt = "导入"
14、showsHiddenFiles:是否显示隐藏文件(.开头的文件)。
panel.showsHiddenFiles = true

15、treatsFilePackagesAsDirectories:.app 等包是否视为文件夹。
panel.treatsFilePackagesAsDirectories = true
16、accessoryView:自定义底部视图,例如格式选项。
在 NSOpenPanel 或 NSSavePanel 底部添加一个 popup 按钮,供用户选择文件格式。
let panel = NSSavePanel()
// 1. 创建 accessoryView(自定义视图)
let formatPopup = NSPopUpButton(frame: NSRect(x: 0, y: 0, width: 200, height: 26))
formatPopup.addItems(withTitles: ["PNG", "JPEG", "TIFF"])
panel.accessoryView = formatPopup
panel.isAccessoryViewDisclosed = true // 默认展开
// 2. 其他常规设置
panel.title = "导出图片"
panel.nameFieldStringValue = "image.png"
panel.allowedFileTypes = ["png"]
// 3. 弹出面板
if panel.runModal() == .OK, let url = panel.url {
let selectedFormat = formatPopup.titleOfSelectedItem
print("保存到: \(url.path)")
print("用户选择的格式: \(selectedFormat ?? "")")
}

总结
NSOpenPanel可以实现用户选择某个文件夹或图片、文件,支持批量导入。
当NSOpenPanel获取文件路径后,就可以直接访问文件,并且具备访问权限。
1、非沙盒(非 App Store)应用:获得路径后,可以自由读取、写入该路径下的文件。
2、沙盒(App Store 或启用 App Sandbox)应用:
仍然可以访问用户选中的文件,因为 NSOpenPanel 是用户授权访问的官方方式。
应用会获得的 URL 会携带一个“安全范围访问权限(security-scoped bookmark)”,可以用它来在后续使用中访问文件。