How to display the file open dialog in AppKit

AppKit’s NSOpenPanel class can be used to display the macOS standard file open dialog. In addition to the function of selecting files to open, the file open dialog has the important function of giving Sandboxed apps access to specified directories on the file system.

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

TOC

Run the file open dialog

The NSOpenPanel class is a type of window that inherits from the NSWindow class. To execute a file open dialog, the flow is as follows.

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

Set selectable file types

Sets the selectable file types. Use the following property.

var allowedContentTypes: [UTType] { get set }

Specify the selectable file types in an array of UTIs to allowedContentsTypes. For example, if JPEG and PNG files are selectable, then 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 }

This property is designated as Deprecated in macOS 12.0, so it is more appropriate to use it differently depending on the operating system as follows.

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 file open 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

The directory that appears by default in the file open dialog is set to the following property.

var directoryURL: URL? { get set }

For example, the following code displays the “Pictures” folder by default.

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 select 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, but 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 oepn dialog are allowed to be read or written. To do so, the app must implement the behavior of displaying the dialog and having the user select the file, and the entitlement must also be configured to do so.

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

Serialized Articles

This article is part of a series of articles on “How to create macOS Apps with AppKit”. For other articles in the series, please open the following links.

How to create macOS Apps with AppKit

Let's share this post !

Author of this article

Akira Hayashiのアバター Akira Hayashi Representative, Software Engineer

I am an application developer loves programming. This blog is a tech blog, its articles are learning notes. In my work, I mainly focus on desktop and mobile application development, but I also write technical books and teach seminars. The websites of my work and books are here -> RK Kaihatsu.

TOC