Mac AppでWindowからfileやdirectoryを選択してpathを取得するやり方
Mac Appの開発へ乗り出し
iTunesで曲を管理しているが、不便に感じていることがあるため、その辺の利便性をなんとかしたいと思い、Mac Appの開発を気ままに進めることにした。
ひとまずやりたいこと
- directoryを参照して、その配下にあるfile(subdirectory配下も含む)を列挙
コードと自分向けへの説明
下記のWindowを表示し、そこからdirectoryを選択させたい
- NSOpenPanelの
begin
メソッドで目的のWindowは表示できる - NSOpenPanelはPropetyによって、file選択、複数選択等を切り替えられる
@IBAction func openPanel(_ sender: NSButton) { let panel = NSOpenPanel() // fileを選択可能にするかどうか。defaultは、true panel.canChooseFiles = false // 複数選択可能にするかどうか。defaultは、false panel.allowsMultipleSelection = false // directoryを選択可能にするかどうか。defaultは、false panel.canChooseDirectories = true // 開始 panel.begin { response in // OK以外に`cancel`, `abort`, `stop`, `continue`があるが、`OK`, `cancel`以外は異常系 guard response == .OK else { return } // closure内でのみ選択したdirectoryのpathが取れる // また、panelの持つurlは、file protocol(file://)がついている self.readItems(url: panel.url) } }
NSOpenPanelで選択したdirectory配下のfileを列挙する
- 先ほどのコードでdirectoryのpathまでは取得できるようになったので、ファイルを列挙する
- FileManagerの
enumerator
メソッドで列挙可能 enumerator
のincludingPropertiesForKeys
で、列挙するfileの各種propertyも取捨できるのかと思ったが、後続のresourceValues
の時に指定したら取れているのでObj-C時代は必要だったが、今は不要?enumerator
のoptions
で、隠しファイルやsubdirectory配下も含めるかを指定可能enumerator
のclosure部分はerror handlerなので、必要に応じて書く
func readItems(url: URL?) { guard let url = url else { return } guard let directoryPath = URL(string: url.path) else { return } // includingPropertiesForKeysの意味あるのか? let enumerator = FileManager.default.enumerator(at: directoryPath, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants]) { (url, error) -> Bool in // closuerは、errorハンドルのみ print(error) // trueならerrorでも継続、falseなら停止 return true } // 列挙 for element in enumerator! { guard let url = element as? URL else { return } print(url) let resourceValue = try! url.resourceValues(forKeys: [.isDirectoryKey, .nameKey, .isHiddenKey]) // forKeysで指定していないものは、nilになる print(resourceValue.isDirectory) print(resourceValue.name) print(resourceValue.isHidden) print(resourceValue.isPackage) print(resourceValue.localizedName) } }