I'm trying to create an NSManagedObject subclass that manages a single file external to the Core Data database targeting back to MacOS 10.14. I don't think I can use the in built feature to store externally, as one of my use-cases is to have the managed file be accessible by QLPreviewItem, which only accepts a URL, not transformed data.
I'm storing the file name in the managed object, and constructing a file path URL on demand with the (known) directory and the file name. The basic behaviours of adding and deleting, even renaming the file (through the application) is all easy. I'm trying to add Undo/Redo support but keep coming into edge conditions where I get it mostly working, but then find some other case in testing where it breaks.
I've been basing my work on this excellent question.
@objc var filepath: URL? {
get {
willAccessValue(forKey: #keyPath(File.filepath))
defer { didAccessValue(forKey: #keyPath(File.filepath)) }
guard primitiveValue(forKey: #keyPath(File.filepath)) == nil else {
return primitiveValue(forKey: #keyPath(File.filepath)) as? URL
}
setPrimitiveValue(file_directory.appendingPathComponent(primitiveValue(forKey: #keyPath(File.filename)) as! String), forKey: #keyPath(File.filepath))
return primitiveValue(forKey: #keyPath(File.filepath)) as? URL
}
}
And then in didSave()
I'm checking for deletion and moving the file to the trash, and implementing restoring of the file in awake(fromSnapshotEvents:)
.
These managed files are typically in to-one
relationships to other objects which can have many managed files, so I handle this by creating a child context and presenting a sheet to the user which contains a table with their managed files. This is a pattern that I've found works well to coalesce undo/redos of the entire sheet. However, this is where I encounter a lot of edge cases in trying to manage the files. The child context seems to need different undo/redo rules to the parent context after being saved back, but I then need a way to pass status information back to the parent context.
For example, if the user deletes a file, it will be moved to the trash when the child context saves itself to the parent context, but then the parent context needs to know the path to the file in the trash to restore the file should the user want to undo all operations in the sheet.
The behaviour and status information appears to be different depending on whether the child context is active, and again depending on whether the parent context is saved or not. Is there any good sample code that covers managing external data in this way? I feel like I'm playing whack-a-mole and have way to many checks for the state of the parent context. This must be a solved problem, but I haven't really found much other than this being the recommended approach a few years ago.