2 Replies
      Latest reply on Jul 17, 2019 7:26 PM by benspratling4
      benspratling4 Level 1 Level 1 (0 points)

        My document format will include many media files, images, audio, & videos.  With simple data model changes, I just store my data for the undo stack in the closures that I store in the NSUndoManager.  When we're talking about kilobytes, that's not an issue, even for 1000's of changes.  But for media files, I don't want them stored in RAM because they're too big, but I'm not sure whether NSFileWrapper can handle undo automatically some how, or if I should manually throw them in a temp dir, or put them in an NSCache so old ones can be deleted or what?

        And since I'm going to need URL's to make the videos work (with AVFoundation, etc...) it seems like NSFileWrapper isn't a great way to move forward.

        What's the easiest to implement solution for package document with interal multimedia files with standard expected behavior here?

        • Re: undo for package-document with video files?
          QuinceyMorris Level 8 Level 8 (6,050 points)

          There aren't any really good answers to be had. Documents containing media files are kinda bad news, because they're big. That imposes a penalty on simple things we often do with documents (such as making a copy before we start editing, to keep multiple versions around), and it's complicated working with big documents programmatically.


          That's why many apps that manipulate lots of media either don't use the document metaphor, or use the document metaphor but keep the media files explicitly in some sort of library, which is more or less managed separately by the user.


          NSFileWrapper has nothing to help you with undo, because it's for opening and saving, not for editing. A NSCache is probably not going to help, because you want data that's used by an undo action to keep its files. You don't want things getting deleted from the cache when they're still in use. (You can force things to stay in the cache for as long as you need them, but in effect you'd be managing the files manually, so the cache doesn't buy you anything.)


          So, you're basically left with the temp directory strategy. One approach is to define a custom class that wraps a URL property that you use in your document and your undo chain to refer to files, instead of using URLs directly. You can implement "deinit" in the custom class to delete the file when the instance deallocates.


          However, there's a problem that you don't really get control to clean up stranded files if your app crashes (or, for that matter, terminates, since it's not guaranteed that "deinit" methods are invoked when your app's process terminates). Temp folders do get cleaned up at reboot, usually, but it's probably not pro-active enough for your needs.


          So, you don't really want to just put media files in an actual temp folder. One alternative is to use subfolders of your Application Support folder, since you can enumerate those at app launch and delete them. You would have one subfolder (with a unique name) for each open document, and you would normally delete it when the document closes. You would also need to copy files from this subfolder to the document during a save, if you want your undo chain to roll back over save boundaries.


          This is all doable, but needs to be carefully programmed to get all the edge cases and race conditions handled.

            • Re: undo for package-document with video files?
              benspratling4 Level 1 Level 1 (0 points)

              Thanks, it hadn't occured to me how seldom the temp folder is deleted.

              I did some digging around in Final Cut Pro X's Info.plist, and as far as I can tell, they are actually using NSDocuments at some level.

              I actually have two levels of abstraction, one that works well as a library, but the files are all tiny json files, and the second are my monsters, which really need to be documents.  I ditched the NSFileWrapper, and overwrote func read(from url: URL, ofType typeName: String) throws and func write(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType, originalContentsURL absoluteOriginalContentsURL: URL?) throws.


              Theoretically, apfs deals with all the copying efficiently, and the NSDocument superclass means the race conditions aren't issues, but I am having some intermitent trouble with autosaving.  As long as I'm sure to manually save the docs, it seems fine, but auto saved docs can loose their large sub-files somehow.  Apparently, I don't fully understand when that last copy needs to be made?