沙箱下的NSOpenPanel-访问“用户选定”文件夹中的所有文件

时间:2019-03-18 09:25:07

标签: macos cocoa sandbox nsopenpanel

我的沙盒装 macOS应用程序按照惯例通过NSOpenPanel模态窗口导入用户选择的图像文件。

首先,我将面板配置为canChooseDirectories = false,并将allowedFileTypes属性设置为NSImage.imageTypes。到目前为止一切顺利。

使用该应用程序,我意识到,要导入的图像更多时候不是全部分组在一个文件夹中,而没有更多内容。如果我可以让用户仅选择包含的文件夹并在“批发”中导入图像,那就太好了,所以我采用了以下代码:

let panel = NSOpenPanel()

panel.allowsMultipleSelection = true
panel.canChooseDirectories = true
panel.canCreateDirectories = false
panel.canChooseFiles = true
panel.allowedFileTypes = NSImage.imageTypes

panel.begin { [unowned self] (result) in
    guard result == .OK else {
        return // User cancelled
     }

     // Read all selected images:

     let urls: [URL] = {
        if let directory = panel.directoryURL {
            // .........................................
            // [A] One directory selected:

            do {
                let urls = try FileManager.default.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil, options: [])
                return urls
            } catch {
                // (I ALWAYS END UP HERE)

                print(error.localizedDescription)
                return [] 
            }
        } else {
            // .........................................
            // [B] One or more files selected:

            return panel.urls
        }
     }()

 // (next: read individual urls...)

...但是try语句总是失败,执行catch块并且抛出的错误是:

  

“由于您无权查看文件“ MyImageFolder”,因此无法打开它。”

是否有解决沙盒应用程序的方法?我忘记了什么,可以让我读取用户选择的文件夹的内容吗?


附录: Apple's documentation指出:

  

应用程序的用户指定他们要使用文件或文件夹时,系统会将关联的路径添加到应用程序的沙箱中。举例来说,用户将〜/ Documents文件夹拖到应用程序的Dock磁贴上(或拖到应用程序的Finder图标上,或拖到应用程序的打开窗口中),从而表明他们要使用该文件夹。作为响应,系统会将〜/ Documents文件夹,其内容及其子文件夹提供给您的应用。

(重点是我的)

1 个答案:

答案 0 :(得分:0)

我过早接受了@vadian's quick answer,但似乎我可以NSOpenPanel访问用户选择的文件夹中的各个文件。

在阅读this answer(我一开始在某种程度上错过了我的搜索)后,我发现下面的代码有效:

// Warning! This code does not deal with the user selecting 
// multiple folders!

let urls: [URL] = {

    if inputURLs.count == 1, inputURLs[0].hasDirectoryPath {
        // Folder; Read its contents:
        do {
            let urls = try FileManager.default.contentsOfDirectory(at: inputURLs[0], includingPropertiesForKeys: nil, options: [])
                return urls

        } catch {
            // (todo: Handle Errors)
            return []
        }
    } else {
        // One or more images; Read them directly:
        return inputURLs
    }
}()

我似乎犯的另一个错误是使用NSURL的{​​{1}}属性来区分所选文件夹和单个文件:它为文件夹返回isFileURL也是!

因此,当我从使用true切换为使用panel.directoryURL(当panel.urls[0]isFileURL时)后,我的应用尝试从目录URL读取单个图像。没有违反沙箱的行为,但也没有读取图像。

根据文档,该属性返回true“如果接收者使用文件方案”(无论如何)。我猜文件夹也“使用文件方案”。 按照this other answer的建议,我改用true