5
votes

I would like to create an app that uses

  • Swift
  • CoreData
  • 'Documents' which work in the standard macOS fashion [custom extension, a single 'file'/filewrapper containing all data relating to that document]

This does not appear possible. The documentation states very clearly that

NSPersistentDocument does not support some document behaviors: File wrappers. [..]

which makes me think that the usual ways of dealing with images in CoreData - binary data with 'allow external storage' and save them to a different location, store the URL in the database - cannot be used with NSPersistentDocument. I want my users to be able to do the usual Finder operations on my 'file' (duplicate, move to external storage, restore from external backup) and need all my data to be in one single package.

The SQL version of the file store results in the usual three-fold stack when saving - .sqlite, .sqlite-shm, .sqlite-wal - which is useless as a 'document'.

Is there a solution I have overlooked? (examples are very sparse; the Big Nerd Ranch sample does not solve this, either; neither Marcus Zarra nor Objc.io touch on NSPersistentDocument).

2

2 Answers

4
votes

The only option that will work with NSPersistentDocument the way you want it is to store the images directly in the database. You need a Binary Data attribute on your entity, but you cannot turn on the Allows External Storage option.

If you turn on this option, Core Data will decide - depending on the size - whether to store the image directly in the database or in a hidden folder inside the folder where your document is located:

Hidden Folder

(I made the folder visible entering cmd-shift-. in the Finder). The sample document is named Test 1.doof and it contains three images:

Document Window

You can see that the hidden folder .Test 1_SUPPORT/EXTERNAL DATA contains two files, which are the two bigger images (1.3 MB and 494 KB). The third one with only 50 KB is stored inside Test 1.doof. If you move Test 1.doof into another folder, the hidden folder is left behind. Opening the file in that other folder leads to two missing images.

Storing the images inside the database is not that bad if you put the binary data into a separate entity with a one-to-one relation to the rest of the data, like so:

Data Model

That way the image does not interfere with any search or sort operation. NSPersistentDocument gives you a lot of cool functionality for free, so you should use it anyway if possible.

Two additional remarks:

  • If you turn on Allows External Storage for an attribute, you do not have to care about URLs or where to store the images, Core Data does that for you (but not in a useful way for document-based apps).
  • These shm or wal files are temporary files that appear "sometimes", for databases without external storage as well. If they stick, you can safely remove them when you app is closed.
1
votes

If you want to put more then just a database in your document, then you should implement NSDocument instead of NSPersistentDocument. In that case you don't get built-in support for CoreData, but you can use your document as a container for multiple file types.

See also Is NSDocument and CoreData a possible combination, or is NSPersistentDocument the only way?