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

1

1

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.

Surah answered 30/11, 2017 at 17:32 Comment(0)
S
1
  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.
Stockman answered 30/11, 2017 at 19:52 Comment(3)
Thanks Andy. 1. The app does handle looking at the version and updating the data from that. Is your concern that someone with an earlier version would try to restore with data from a later version? 2. I am not having users share via iCloud - just store the backups there. But a user can create an email with an attachment of a backup from their iCloud backup. I was probably going to use iCloud Documents (as opposed to CloudKit). Does that sound all good?Surah
1. Yes it’s possible that user with earlier version picks up the store from the newer version. It’s also possible that the much newer app picks up a very old store. As long as you can do lightweight migrations or you run progressive migration you should be fine. As of using newer store in older app, I bet it’s impossible since the app would not know what to do with it.Stockman
2. Cloud documents should work just fine. NSMetadataQuery can help you monitor or search files in container even when they are not available on disk. Copying files from the iCloud documents container is better done with NSFileCoordinator. It’s pain to use it but if you do that for copying from container that should work just fine. NSFileManager.setUbiquitous is a nice shortcut but it actually moves files, you may want to copy from iCloud when you wish to restore the core data store from iCloudStockman

© 2022 - 2024 — McMap. All rights reserved.