AppKitのNSOpenPanel
クラスを使うと、macOS標準のファイル選択ダイアログを表示できます。ファイル選択ダイアログは、開くファイルを選択するという機能の他に、Sandbox化されたアプリに対して、ファイルシステム上の指定したディレクトリに対するアプリからのアクセス権を与えるという重要な機能があります。
この記事では、AppKitのNSOpenPanel
クラスの使い方を解説します。
ファイル選択ダイアログを実行する
NSOpenPanel
クラスはNSWindow
クラスを継承しているウインドウの一種です。ファイル選択ダイアログを実行するには、次のような流れになります。
- ダイアログの設定を行う
runModal
メソッドを使ってモーダルダイアログとして実行する。- 選択された項目を取得する。
選択可能なファイルタイプを設定する
選択可能なファイルタイプを設定します。次のプロパティを使用します。
var allowedContentTypes: [UTType] { get set }
allowedContentsTypes
に選択可能なファイルタイプをUTIの配列で指定します。例えば、JPEGファイルとPNGファイルを選択可能なら次のようになります。
let openPanel = NSOpenPanel()
openPanel.allowedContentTypes = [.jpeg, .png]
但し、このプロパティはmacOS 11以降でのみ使用可能です。次のプロパティに拡張子の配列を設定します。
var allowedFilesTypes: [String]? { get set }
このプロパティはmacOS 12.0でDeprecatedに指定されているので、次のようにOSによって使い分ける方が適切です。
let openPanel = NSOpenPanel()
if #available(macOS 11.0, *) {
openPanel.allowedContentTypes = [.jpeg, .png]
} else {
openPanel.allowedFileTypes = ["jpg", "png"]
}
モーダルダイアログとして実行する
runModal
メソッドを実行すると、ファイル選択ダイアログをモーダルダイアログとして実行できます。
func runModal() -> NSApplication.ModalResponse
「Open」ボタンがクリックされると、.OK
が返され、「Cancel」ボタンがクリックされると「.cancel」が返されます。次のように戻り値をアプリ側で判定します。
func selectFile() {
let openPanel = NSOpenPanel()
if #available(macOS 11.0, *) {
openPanel.allowedContentTypes = [.jpeg, .png]
} else {
openPanel.allowedFileTypes = ["jpg", "png"]
}
let modalResponse = openPanel.runModal()
if modalResponse == .OK {
}
}
選択されたファイルを取得する
選択されたファイルは次のプロパティに格納されます。
var urls: [URL] { get }
例えば、次のコードは選択されたファイルをコンソールに出力します。
func selectFile() {
let openPanel = NSOpenPanel()
if #available(macOS 11.0, *) {
openPanel.allowedContentTypes = [.jpeg, .png]
} else {
openPanel.allowedFileTypes = ["jpg", "png"]
}
let modalResponse = openPanel.runModal()
if modalResponse == .OK {
openFiles(urls: openPanel.urls)
}
}
func openFiles(urls: [URL]) {
for url in urls {
print("\(url)")
}
}
デフォルトディレクトリを設定する
ファイル選択ダイアログでデフォルトで表示されるディレクトリは、次のプロパティに設定します。
var directoryURL: URL? { get set }
例えば、次のコードは「ピクチャ」フォルダをデフォルトで表示します。
openPanel.directoryURL = try! FileManager.default.url(for: .picturesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
ディレクトリを選択する方法
次のプロパティをtrue
に設定すると、ディレクトリを選択できるようになります。
var canChooseDirectories: Bool { get set }
また、次のプロパティをfalse
にするとファイルを選択できなくします。
var canChooseFiles: Bool { get set }
この2つのプロパティの値を設定すると、ディレクトリだけを選択可能にしたり、ファイルとディレクトリを両方とも選択可能にしたりできます。
複数ファイルを選択する方法
NSOpenPanel
はデフォルトでは選択可能なファイルは1つだけですが、次のプロパティをtrue
に設定すると、複数のファイルを選択できるようになります。
var allowsMultipleSelection: Bool { get set }
例えば、次のようになります。
func selectFile() {
let openPanel = NSOpenPanel()
openPanel.allowsMultipleSelection = true
openPanel.directoryURL = try! FileManager.default.url(for: .picturesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
if #available(macOS 11.0, *) {
openPanel.allowedContentTypes = [.jpeg, .png]
} else {
openPanel.allowedFileTypes = ["jpg", "png"]
}
let modalResponse = openPanel.runModal()
if modalResponse == .OK {
openFiles(urls: openPanel.urls)
}
}
func openFiles(urls: [URL]) {
for url in urls {
print("\(url)")
}
}
Sandboxのエンタイトルメントの設定
Sandbox化されたアプリの場合は、ファイル選択ダイアログでユーザーが選択したファイルや、選択したディレクトリ及びサブディレクトリのみ読み書きが許可されます。そのためには、ダイアログを表示して選択してもらうという動作をアプリ側で実装する他、エンタイトルメントにもその設定が必要です。
アプリのターゲットの設定を開き、「Signing & Capabilities」タブを開き、「App Sandbox」の「File Access」の設定で、次の項目を設定します。
Type | 説明 |
---|---|
User Selected File | ファイル選択ダイアログで選択された項目のアクセス権 |
Downloads Folder | ダウンロードフォルダのアクセス権 |
Pictures Folder | ピクチャフォルダのアクセス権 |
Music Folder | ミュージックフォルダのアクセス権 |
Movies Folder | ムービーフォルダのアクセス権 |
アクセス権は次の3種類があります。
Permission & Access | 説明 |
---|---|
None | アクセス権無し |
Read Only | 読み込み専用 |
Read/Write | 読み書き可能 |