How to display the open file dialog in AppKit

AppKit’s NSOpenPanel class can display the standard macOS file open dialog. In addition to selecting files to open, the open file dialog gives Sandboxed apps access to specified directories on the file system.

This article explains how to use AppKit’s NSOpenPanel class.

TOC

Run the open file dialog

The NSOpenPanel class is a type of window that inherits from the NSWindow class. You can execute a file open dialog by following the steps below.

  1. Configure dialog settings.
  2. Run as the modal dialog with the runModal method.
  3. Get the selected items.

Set selectable file types

Use the following property to set the selectable file types.

var allowedContentTypes: [UTType] { get set }

Specify the selectable file types in an array of UTIs to the allowedContentsTypes property. For example, if JPEG and PNG files are selectable, the code is as follows.

let openPanel = NSOpenPanel()
openPanel.allowedContentTypes = [.jpeg, .png]

However, this property is only available on macOS 11 or later. Set the following property to an array of extensions on earlier OSs.

var allowedFilesTypes: [String]? { get set }

Given this property is marked as Deprecated in macOS 12.0, it’s more appropriate to adapt its usage depending on the operating system.

let openPanel = NSOpenPanel()

if #available(macOS 11.0, *) {
	openPanel.allowedContentTypes = [.jpeg, .png]
} else {
	openPanel.allowedFileTypes = ["jpg", "png"]
}

Run as a modal dialog

The runModal method allows you to run the open file dialog as a modal dialog.

func runModal() -> NSApplication.ModalResponse

.OK is returned when the “Open” button is clicked, and .cancel is returned when the “Cancel” button is clicked. The application determines the return value as follows.

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 {
        
    }
}

Get the selected files

The selected file will be stored in the following property.

var urls: [URL] { get }

For example, the following code outputs the selected file to the console.

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)")
    }
}

Set default directory

You can assign the following property to set the default directory of the open file dialog.

var directoryURL: URL? { get set }

For example, the following code initially navigates to the “Pictures” folder in the open file dialog.

openPanel.directoryURL = try! FileManager.default.url(for: .picturesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)

How to select a directory

Set the following property to true to allow selecting the directory.

var canChooseDirectories: Bool { get set }

Also, setting the following property to false will disable file selection.

var canChooseFiles: Bool { get set }

By setting the values of these two properties, you can make only directories selectable or both files and directories selectable.

How to select multiple files

NSOpenPanel allows only one file to be selected by default. Still, multiple files can be selected by setting the following property to true.

var allowsMultipleSelection: Bool { get set }

For example,

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 Entitlement Settings

In the case of a sandboxed app, only files, directories, and subdirectories selected by the user in the file open dialog are allowed to be read or written. Therefore, the app must implement the behavior of displaying the dialog and having the user select the file. You must also configure the entitlement accordingly.

Open the app’s target settings, go to the “Signing & Capabilities” tab, and in the “File Access” setting in “App Sandbox”, set the following items.

Type Description
User Selected File Access rights for the item selected in the file open dialog.
Downloads Folder Download folder access rights.
Pictures Folder Picture folder access rights.
Music Folder Music folder access rights
Movies Folder Movie folder access rights
File Access

There are three types of access rights.

Permission & Access Description
None No access rights
Read Only Read only
Read/Write Read/Write
Permission & Access
Edit entitlements in Xcode
Edit entitlements in Xcode

Authored Books

Let's share this post !

Author of this article

Akira Hayashi (林 晃)のアバター Akira Hayashi (林 晃) Representative(代表), Software Engineer(ソフトウェアエンジニア)

アールケー開発代表。Appleプラットフォーム向けの開発を専門としているソフトウェアエンジニア。ソフトウェアの受託開発、技術書執筆、技術指導・セミナー講師。note, Medium, LinkedIn
-
Representative of RK Kaihatsu. Software Engineer Specializing in Development for the Apple Platform. Specializing in contract software development, technical writing, and serving as a tech workshop lecturer. note, Medium, LinkedIn

TOC