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



我正在尝试提取用户在默认情况下选择的文档的URL"打开";我的基于文档的macOS应用程序的对话。我知道,fileWrapper被传递给init方法,但有没有一种方法可以从所述包装器中提取路径/URL?

谢谢,

Lars

DocumentGroup只需要绑定到文档来初始化ContentView,所以在文档上有一个函数来获取url&返回绑定:

应用程序:

import SwiftUI
@main
struct FileOpenApp: App {
var body: some Scene {
DocumentGroup(newDocument: FileOpenDocument()) { file in
ContentView(document: file.document.setSourceURL(file))
}
}
}

文件:

struct FileOpenDocument: FileDocument {
var sourceURL: URL?

init() {
}
// needs to be mutating to avoid "self is immutable" error
mutating func setSourceURL(_ config: FileDocumentConfiguration< FileOpenDocument >) -> Binding<FileOpenDocument> {
sourceURL = config.fileURL
return config.$document
}
} 

如果有人单击"打开"(OK(按钮,打开面板会为您提供URL。NSOpenPanel具有包含所选文件的URL的urls属性。

如果打开成功,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。以下文章应该会有所帮助:

在基于SwiftUI的macOS应用程序中保存和打开面板

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

非居民外国人接受的答案可以简化,DocumentGroup闭包需要绑定到文档来初始化ContentView,因此在文档上声明一个函数来获取源URL&返回配置,然后该配置可以提供文档绑定:

struct FileOpenDocument: FileDocument {
var sourceURL: URL?

mutating func setSourceURL(config: FileDocumentConfiguration<FileOpenDocument>) -> FileDocumentConfiguration<FileOpenDocument> {
sourceURL = config.fileURL
return config
}
} 

DocumentGroup初始值设定项随后变为:

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

无需修改ContentView。

不能将FileDocument声明为具有可变方法的结构。这样做将触发可怕的从视图内发布更改。不允许更新,这将导致未定义的行为问题。在Apples解决这个问题之前,我们应该坚持将FileDocument声明为类,而不是Struct。这是为了规避问题,而不是解决问题,因为大多数时候都需要使用structs。

我的解决方案是将我的文件文档声明为类。这是我正在做的一个实验:

class MyDocument: FileDocument {
var pdfURL: URL?
var pdfFile: PDFDocument?
init(pdfDocument: PDFDocument = PDFDocument()) {
pdfFile = pdfDocument
}
static var readableContentTypes: [UTType] { [.pdf] }
required init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents
else {
throw CocoaError(.fileReadCorruptFile)
}
pdfFile = PDFDocument(data: data)
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
return .init()
}

func setSourceURL(config: FileDocumentConfiguration<GPTFileDialogDocument>) -> FileDocumentConfiguration<GPTFileDialogDocument> {
pdfURL = config.fileURL
return config
}
}

通过这种方式,您可以保留与@dang建议的相同的DocumentGroup初始值设定项:

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

最新更新