UIManagedDocument and CoreData

Hi Guys,


I am testing a document-based CoreData database with iCloud-UIManagedDocument (using Swift 2) but the document it creates is initially a directory with the database files in it. But i’am looking for the single-file type. Does anyone know how to change the internal filewrapper to build a single-file document? One of the problems is that CoreData adds some extra SHM and WAL files from time to time and the second problem is that database files are not just flatfile types.


Hope someone can help me out

Replies

The database file won't be "just flatfile types" if you turn off the WAL option, either, though. Probably more importantly, CoreData with iCloud support tries to do record-based work instead of file-based work to avoid the whole "You updated five bytes in a 100k file, but now you have to re-upload the whole 100k file" problem.


So what, exactly are you trying to do?

First of all thanks for responding to my question.



UIManagedDocument is a subclass of UIDocument. And the documentation of UIDocument say’s to create a subclass of UIDocument and override two methods contentsForType:error and loadFromContents:ofType:error and create your own NSFileWrapper objects if you like (or must).

NSFileWrapper on its behalf can create 3 kinds of files:

a Regular-file file wrapper (which is the one i’am looking for)

a Directory file wrapper (which to one i’am getting now)

and a Symbolic-link file wrapper (which is of no use for me)



Initially a UIManagedDocument object with support for iCloud creates a directory on the iCloud-drive and in that directory it creates yet another directory and in there it puts my database-file and an SHM- and a WAL-file.

So I end up with some directory’s and my database files.

The solution I’am looking for is a “Regular-file file wrapper” so that there will be only one file which includes my database files instead of a directory with a bunch of database files.

There are some code snippets and sample projects on how to create a custom filewrapper in a UIDocument based object, but to my knowledge there are no samples on how to customize UIManagedDocuments objects to support a single file database.


In a UIDocument object you can create and manage the filewapper yourself, but the problem I’am struggling with is that the database files which UIManagedDocument creates isn’t something I manage myself, its done by CoreData’s store coordinator.



Note:

I already inserted the following code in my info.plist

<key>CFBundleDocumentTypes</key>

<array>

<dict>

<key>CFBundleTypeExtensions</key>

<array>

<string>boxdat</string>

</array>

<key>CFBundleTypeIconFiles</key>

<array>

<string>Icon-iPad-doc320.png</string>

<string>Icon-iPad-doc.png</string>

<string>Icon-iPhone-doc44.png</string>

<string>Icon-iPhone-doc.png</string>

<string>Icon-iPad-doc320</string>

</array>

<key>CFBundleTypeName</key>

<string>Boxdat Database</string>

<key>LSHandlerRank</key>

<string>Owner</string>

<key>LSItemContentTypes</key>

<array>

<string>com.johan.managedDocuments.boxdat</string>

</array>

<key>LSTypeIsPackage</key>

<string>YES</string>

</dict>

</array>

Let me try to write this again.


The UIManagedDocument that CoreData creates doesn't do what you're trying to do, because doing that is a bad idea. It's a bad idea because iCloud mirroring of a file that you're going to be making arbitrary 20-byte changes to is horrible and inefficient, so instead CoreData tries to do record-level mirroring. In order to do that, CoreData has to create the system of files and do some other work.


If you insist on interfering with that, and want single-file sqlite mode, see the documentation:

The Core Data SQLite persistent store will default to using WAL journal_mode on all applications linked on or after 10.9 (iOS 7). This mode offers better reliability and performance than the classic SQLite rollback (delete) journaling. WAL journal_mode is not, however, recommended for read-only database files, or for files that need to interoperate with iOS 4 or earlier. To get the previous behavior, add the following dictionary to the store options dictionary you pass to to NSPersistentStoreCoordinator’s addPersistentStoreWithType:configuration:URL:options:error: method:


@{ NSSQLitePragmaOptions : @{ @"journal_mode" : @"DELETE" } }

Well I think we are not on the same bandwidth yet, we are close, but not just there yet 🙂

I don’t want to restrict sqLite in any way. Maybe the following explanation will get us there.


I’am not looking to enforce sqlite to do something CoreData doesn’t like. What I like to have as a result is that all my database files (.sqlite, SHM, WALL) can be put in a single file-package.

Take for example a Pages-file. The user see’s only one file but that file is actually a file-package with some directory’s, images an other stuff in it, and thats what i’am trying to achieve.


To my knowledge this kind of file-package can be created by the UIDocument class as mentioned before using the NSFileWrapper class. But in the case of UIDocument you have control over everything, like reading and writing your data. But using coreData from within a UIManagedDocument I don’t have control over reading an writing data, this is done by CoreData and the managed-object itself. You can override the same methods as in UIDocument but there is no explanation on how this is done in a UIManagedDocument object.


So instead of getting the default: a directory with some database files, I would like to have the database files in a file-package so the user only has to copy or move one file around witch is safer to use. We know that if the user copy’s or move’s 3 out of 4 files around he/she would loose data.

Hope this is a better explanation of the path I wanna walk.

You want a File Wrapper - see article linked

https://www.swiftdevjournal.com/using-file-wrappers-in-a-swiftui-app/