如何从基于 SwiftUI 文档的应用程序中将多个文件保存在包文件夹中?
Posted
技术标签:
【中文标题】如何从基于 SwiftUI 文档的应用程序中将多个文件保存在包文件夹中?【英文标题】:How do I save multiple files in a package folder from a SwiftUI Document Based App? 【发布时间】:2021-09-24 19:40:40 【问题描述】:我正在开发一个基于 SwiftUI 文档的应用程序,其中包含一些易于序列化的数据和多个图像。我想将文档保存为一个包(即文件夹),其中一个文件包含易于序列化的数据,另一个子文件夹包含图像作为单独的文件。我的包目录应该是这样的:
<UserChosenName.pspkg>/. // directory package containing my document data and images
PhraseSet.dat // regular file with serialized data from snapshot
Images/ // subdirectory for images (populated directly from my app as needed)
Image0.png
Image1.png
....
我创建了一个 FileWrapper 子类,它设置目录结构并适当地添加序列化快照,但是当我在 ios 模拟器中运行应用程序并单击“+”以创建一个新文档时,应用程序通过 PkgFileWrapper init 运行() 和 write() 没有错误,但返回浏览器窗口而没有明显地创建任何东西。我已声明导出和导入类型标识符符合“com.apple.package”。任何人都可以建议一种方法来使其正常工作吗?
PkgFileWrapper 类如下所示:
class PkgFileWrapper: FileWrapper
var snapshot: Data
init(withSnapshot: Data)
self.snapshot = withSnapshot
let sWrapper = FileWrapper(regularFileWithContents: snapshot)
let dWrapper = FileWrapper(directoryWithFileWrappers: [:])
super.init(directoryWithFileWrappers: ["PhraseSet.dat" : sWrapper,
"Images" : dWrapper ])
// NOTE: Writing of images is done outside
// of the ReferenceFileDocument functionality.
override func write(to: URL,
options: FileWrapper.WritingOptions,
originalContentsURL: URL?) throws
try super.write(to: to, options: options,
originalContentsURL: originalContentsURL)
required init?(coder inCoder: NSCoder)
fatalError("init(coder:) has not been implemented")
【问题讨论】:
我实际上需要相同的,但我遇到了沙盒问题。我需要它来创建一个文件夹并将文档放在该文件夹中。然后在我的主文件夹中,它会为图像等创建子文件夹......但我不知道如何设置它,我想我可能会遇到沙盒问题。 @John,请看下面我编辑的答案。如果您使用的是 FileDocument 或 ReferenceFileDocument 类,那么它应该为您提供一个不应该有沙盒问题的基本 URL。 【参考方案1】:解决方案是不要覆盖 PkgFileWrapper.write(...)。如果在 init(...) 中正确设置了目录结构,则将自动创建文件和目录。上面重写的 write(...) 函数现已更正。
如果您想将图像写入图像子目录,您可以执行以下操作:
func addImage(image: UIImage, name: String)
let imageData = image.pngData()!
imageDirWrapper.addRegularFile(withContents: imageData,
preferredFilename: name)
imageDirWrapper 的值是与保存图像的目录相对应的目录包装器,如上面的 PkgFileWrapper.init() 中创建的。您需要记住的一个关键概念是“写入”函数将在适当的时间自动调用 - 您无需明确写出图像数据。 ReferenceFileDocument 类会为此安排,还会安排您的应用通过适当的 URL 来设置文件包装器。
imageDirWrapper 变量在 ReferenceFileDocument 协议所需的 init(...) 中设置:
required init(configuration: ReadConfiguration) throws
phraseSet = PhraseSet()
if configuration.file.isDirectory
if let subdir = configuration.file.fileWrappers
// first load in the phraseSet
for (name, wrapper) in subdir
if name == PkgFileWrapper.phraseSetFileName
if let data = wrapper.regularFileContents
phraseSet = try PhraseSet(json: data)
// next load in the images and put them into the phrases.
for (name, wrapper) in subdir
if name == PkgFileWrapper.imageDirectoryName
if let imageDir = wrapper.fileWrappers
imageDirWrapper = wrapper
for (iName, iWrapper) in imageDir
print("image file: \(iName)")
if let d = iWrapper.regularFileContents
for p in phraseSet.phrases
if p.imageName == iName
// TBD: downsample
var uiD = ImageData(data: d)
if doDownSample
uiD.uiimageData = downsample(data: d,
to: imageSize)
else
_ = uiD.getUIImage()
images[iName] = uiD
else
throw CocoaError(.fileReadCorruptFile)
您可以在此处通过查看传入目录的子目录中的图像目录名称来查看 imageDirWrapper 是如何设置的。还有一些额外的代码:它首先在传入的目录中查找数据文件并将其加载;然后它会查找图像目录并对其进行处理。
【讨论】:
如何将图像写入该文件夹? @John,请看我上面编辑的答案。 此外,斯坦福大学的 Paul Hegarty 在 cs193p.sites.stanford.edu 的 2021 年第 14 讲中对文档架构进行了精彩的讨论,尽管他没有讨论这个确切的问题。 你的 imageDirWrapper 变量在哪里?我在 func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper 中设置了我的 FileWrappers,但是如何将文件添加到这些文件夹中? @John,看看我最近的编辑,显示了 imageDirWrapper 的设置。如果有用,请点赞我的回答!以上是关于如何从基于 SwiftUI 文档的应用程序中将多个文件保存在包文件夹中?的主要内容,如果未能解决你的问题,请参考以下文章
基于文档的 MacOs 应用程序的 SwiftUI 窗口大小
如何在 SwiftUI ForEach 内容中将多个按钮操作分开?
iOS/iPadOS 中的 SwiftUI + DocumentGroup:如何重命名当前打开的文档