4

我正在创建一个 macOS 应用程序,该应用程序在其 Bundle 目录中附带一些 .zip 文件。

用户应该能够将这些文件从我的应用程序保存到自定义目录。

我发现NSSavePanel并认为这是正确的方法——这就是我目前所拥有的:

@IBAction func buttonSaveFiles(_ sender: Any) {

    let savePanel = NSSavePanel()

    let bundleFile = Bundle.main.resourcePath!.appending("/MyCustom.zip")

    let targetPath = NSHomeDirectory()
    savePanel.directoryURL = URL(fileURLWithPath: targetPath.appending("/Desktop")) 
    // Is appeding 'Desktop' a good solution in terms of localisation?

    savePanel.message = "My custom message."
    savePanel.nameFieldStringValue = "MyFile"
    savePanel.showsHiddenFiles = false
    savePanel.showsTagField = false
    savePanel.canCreateDirectories = true
    savePanel.allowsOtherFileTypes = false
    savePanel.isExtensionHidden = true

    savePanel.beginSheetModal(for: self.view.window!, completionHandler: {_ in })

}

我不知道如何“移交”bundleFilesavePanel.

所以我的主要问题是:如何将应用程序包中的文件保存/复制到自定义目录?

其他问题取决于NSSavePanel:1)默认情况下它似乎没有本地化(我的 Xcode 方案设置为德语,但面板显示为英语),我必须自己自定义吗?2)有没有办法显示默认展开的面板?

4

1 回答 1

7

您应该使用Bundle.main.url获取现有文件 URL,然后使用面板获取目标 URL,然后复制文件。该面板不对文件做任何事情,它只是获取它们的 URL。

例子:

// the panel is automatically displayed in the user's language if your project is localized
let savePanel = NSSavePanel()

let bundleFile = Bundle.main.url(forResource: "MyCustom", withExtension: "zip")!

// this is a preferred method to get the desktop URL
savePanel.directoryURL = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first!

savePanel.message = "My custom message."
savePanel.nameFieldStringValue = "MyFile"
savePanel.showsHiddenFiles = false
savePanel.showsTagField = false
savePanel.canCreateDirectories = true
savePanel.allowsOtherFileTypes = false
savePanel.isExtensionHidden = true

if let url = savePanel.url, savePanel.runModal() == NSFileHandlingPanelOKButton {
    print("Now copying", bundleFile.path, "to", url.path)
    // Do the actual copy:
    do {
        try FileManager().copyItem(at: bundleFile, to: url)
    } catch {
        print(error.localizedDescription)
    }
} else {
    print("canceled")
}

另外,请注意是否扩展面板是用户选择,您不能从您的应用程序中强制它。

于 2016-12-17T11:50:25.343 回答