ioscore-databackupdatabase-backupsnspersistentstore

How to create sharable Core Data .sqlite backups locally and in iCloud using current NSPersistentStore methods


I have been having quite a time of figuring out the correct way to create a backup of a Core-Data backed .sqlite file and storing that backup, both locally and/or in iCloud (whatever the user prefers), for download, restore or sharing. Let me state up front that I am not talking about moving the persistent store to iCloud to be used by the app as its datasource. I am simply asking about creating backup files in this question.

In 2014, Apple changed their default journaling mode for Core Data SQLite stores to WAL.

https://developer.apple.com/library/content/qa/qa1809/_index.html

With that change, they recommended:

To safely back up and restore a Core Data SQLite store, you can do the following: Use the following method of NSPersistentStoreCoordinator class, rather than file system APIs, to back up and restore the Core Data store: - (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)error

Note that this is the option we recommend.

Prior to this, I had been using NSFileManager to create backups. With this recommendation, I believe that the correct way to create a backup locally is to add a new persistent store and then to migrate that persistent store to the desired backup location, using the NSPersistentStoreCoordinator methods addPersistentStoreWithType:configuration:URL:options:error, and migratePersistentStore:toURL:options:withType:error, respectively.

My questions are two-fold:

  1. I previously would zip my data to NSData before exporting it, and would write the NSData directly to a file. My file extension would be custom to my app, for sharing the zipped data via email or other iOS sharing methods. With the migratePersistentStore:toURL:options:withType:error method, I now end up with a .sqlite file (and its corresponding WAL file, etc) in the desired location, but I cannot figure out how to share this file now. If I zip the file, won't I be in danger of losing the data I worked hard to preserve by using migratePersistentStore:toURL:options:withType:error in the first place? I believe so, but I do want to enable my users to share/save their backups vie email, etc, and I don't know how to best approach this now.
  2. I am having a hard time understanding how migratePersistentStore:toURL:options:withType:error can be used to backup the file to iCloud. Much like the sharing example above, I see that I can use addPersistentStoreWithType:configuration:URL:options:error, and migratePersistentStore:toURL:options:withType:error to get the desired .sqlite copy locally, but if I then try to upload that local file to iCloud, I fear I will lose the data I worked to preserve by using migratePersistentStore:toURL:options:withType:error in the first place. I have been trying to see if there is a way that I could/should use migratePersistentStore:toURL:options:withType:error to move the newly created persistentStore directly to iCloud, but I haven't been able to find any documentation on how to do that or if it should be done at all. Is there a specific url I would need to use to indicate that the destination for the persistentStore is iCloud?

I would greatly appreciate any insights that can be shared regarding the answers to these questions.


Solution

    1. ZIP should be safe way IMO since it has CRC data for data integrity validation.

    You have to be careful though regarding shared CoreData store version. Suppose two users run different versions of the app and share the CoreData store between each other. CoreData doesn't support progressive migrations out of box. https://www.objc.io/issues/4-core-data/core-data-migration/

    Maybe sharing a portion of data in JSON and re-creating CoreData entities from it would be safer and easier strategy for sharing data as opposed to sharing entire graph.

    1. You can only copy file into iCloud container and share it across devices but you can't really use it directly from container or have incremental updates coming via iCloud. NSFileManager has setUbiquitous that allows to move file into iCloud container.