I need a FileWrapper which contains a file and contains a folder. The file is a single file, and the folder is used to write images to.
The folder also can contain some subfolders. I have a working code, but the issue is that when the Document gets saved, the folder gets re-written which deletes my images and subfolders.
I'm quite sure it has something to do with func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper
but I need some help from somebody with more experience with FileWrappers.
This is my code:
struct MyProject: FileDocument {
var myFile: MyFile
static var readableContentTypes: [UTType] { [.myf] }
init(myFile: MyFile = MyFile() {
self.myFile = myFile
}
init(configuration: ReadConfiguration) throws {
let decoder = JSONDecoder()
guard let data = configuration.file.fileWrappers?["MYFProject"]?.regularFileContents else {
throw CocoaError(.fileReadCorruptFile)
}
do {
self.myFile = try decoder.decode(MyFile.self, from: data)
} catch {
throw error
}
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
let encoder = JSONEncoder()
do {
let data = try encoder.encode(myFile)
let mainDirectory = FileWrapper(directoryWithFileWrappers: [:])
let myfWrapper = FileWrapper(regularFileWithContents: data)
let imagesWrapper = FileWrapper(directoryWithFileWrappers: [:])
let imageSubFolder = FileWrapper(directoryWithFileWrappers: [:])
for numberString in myFile.numbers {
imageSubFolder.preferredFilename = numberString
imagesWrapper.addFileWrapper(imageSubFolder)
}
myfWrapper.preferredFilename = "MYFProject"
mainDirectory.addFileWrapper(myfWrapper)
imagesWrapper.preferredFilename = "MYFImages"
mainDirectory.addFileWrapper(imagesWrapper)
return mainDirectory
} catch {
throw error
}
}
}
I use this path to write images to.
func getSubFolderImageFolder(documentPath: URL, subFolder: String) -> URL {
let sfProjectPath = documentPath.appendingPathComponent("MYFImages").appendingPathComponent(subFolder)
if !FileManager.default.fileExists(atPath: sfProjectPath.path) {
do {
try FileManager.default.createDirectory(atPath: sfProjectPath.path, withIntermediateDirectories: false, attributes: nil)
return sfProjectPath
} catch {
fatalError(error.localizedDescription)
}
}
else {
return sfProjectPath
}
}
Thanks in advance!
CodePudding user response:
Your getSubFolderImageFolder
function is not going to work well with file wrappers. You must use the FileWrapper
methods to create the folders and files in the file wrapper.
To add a subfolder to your images folder, create a directory file wrapper the same way you created the imagesWrapper
folder for the images. Add the subfolder as a child of the images folder.
let imageSubFolder = FileWrapper(directoryWithFileWrappers: [:])
imagesWrapper.addFileWrapper(imageSubFolder)
You must create a directory file wrapper for each subfolder. I notice in your updated code, you have only one subfolder file wrapper. With only one subfolder file wrapper, you have no way to store an image file in the correct subfolder.
To add the images, start by converting each image into a Data
object. Create a regular file wrapper for each image, passing the image data as the argument to regularFileWithContents
. Call addFileWrapper
to add the image file to the appropriate folder.
let imageFile = FileWrapper(regularFileWithContents: imageData)
imageFile.preferredFilename = "ImageFilename" // Replace with your filename.
imagesWrapper.addFileWrapper(imageFile)
You can find more detailed information about file wrappers in the following article: