从标准 Swift 基于文档的应用程序的打开对话框中获取 URL

Get URL from Open dialog of standard Swift document-based application

我正在尝试提取用户在我基于文档的 macOS 应用程序的默认“打开”对话框中选择的文档的 URL。我知道,一个 fileWrapper 被传递给了 init 方法,但是有没有办法从所述包装器中提取 path/URL?

谢谢,

拉斯

FileWrapper 有一个 filename 字段,因此您可能会使用它。

如果有人单击打开(确定)按钮,打开的面板会为您提供 URL。 NSOpenPanel 有一个 urls 属性,其中包含所选文件的 URL。

如果打开成功,SwiftUI 文件导入器会给你一个URL。

.fileImporter(isPresented: $isImporting, allowedContentTypes: 
    [.png, .jpeg, .tiff], onCompletion: { result in
    
    switch result {
        case .success(let url):
            // Use the URL to do something with the file.
        case .failure(let error):
            print(error.localizedDescription)
    }
})

更新

SwiftUI 的文档打开面板与文件导入器的工作方式不同。您可以尝试直接使用 NSOpenPanel。以下文章应该有所帮助:

Save And Open Panels In SwiftUI-Based macOS Apps

我能让它工作的唯一方法是向内容视图添加自定义初始化程序,将 URL 写回文档。非常不优雅,但我们在这里:

应用程序:

import SwiftUI

@main
struct FileOpenApp: App {
    var body: some Scene {
        DocumentGroup(newDocument: FileOpenDocument()) { file in
            ContentView(document: file.$document, fileURL: file.fileURL)
        }
    }
}

文件:

struct FileOpenDocument: FileDocument {
    var text: String
    var originalFilePath: String
    var firstOpen: Bool
    
    
    init(text: String = "Hello, world!") {
        self.text = text
        self.firstOpen = true
        self.originalFilePath = "NewFile Path"
    }

    static var readableContentTypes: [UTType] { [.exampleText, .CSVtext, .plainText] }

    init(configuration: ReadConfiguration) throws {
        guard let data = configuration.file.regularFileContents,
              let string = String(data: data, encoding: .utf8)
        else {
            throw CocoaError(.fileReadCorruptFile)
        }
        text = string
        self.firstOpen = true
        self.originalFilePath = "ReadPath"
    }
    
    func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
        let data = text.data(using: .utf8)!
        return .init(regularFileWithContents: data)
    }
} 

内容视图:

struct ContentView: View {
    @Binding var document: FileOpenDocument
    var documentURL: URL?

    init(document: Binding<FileOpenDocument>, fileURL: URL?){
        self._document = document
        self.documentURL = fileURL

        if document.firstOpen.wrappedValue == true {
            if let path = self.documentURL?.path {
                self.document.originalFilePath = path
                document.firstOpen.wrappedValue = false
            }
        }
    }
    
    var body: some View {
        TextEditor(text: $document.text)
        Text("ContentView Path: \(self.documentURL?.path ?? "no Document Path")")
        Text("Document Path: " + document.originalFilePath)
    }
}