问题
I'm struggling to find any information about creating backups of core data. My ultimate goal is to allow the user to create multiple backups, and restore from a selected backup.
I've found a sample project that allows you backup/restore locally or via iCloud in Objective-C, but nothing in swift.
Can anyone help? Or point me in the right direction. I don't even know where to start with this one.
回答1:
I've never needed to do this but if I did this is what I'd do.
To make backups
At any time, use the following steps:
- Create a new, second Core Data stack. Use either
NSPersistentContainer
or the older (but still supported) method of creating anNSPersistentStoreCoordinator
. - Use
NSPersistentStoreCoordinator
's functionmigratePersistentStore(_:to:options:withType:)
to create the backup. Make the destination URL include something unique, using a UUID or a timestamp. Put the backups in the documents folder. - Keep a list of backups by date. You could put this in
UserDefaults
or create a new property list file to save backup info.
Step #2 will remove the original store from the Core Data stack-- which is why you create a second stack in step #1. This way you can use the second stack to make the backup without affecting the one your app is using.
If you're using NSPersistentContainer
, use its persistentStoreCoordinator
property to carry out step #2.
To restore from backups
This is a little bit tricky because your app may be using its persistent store, but now you want to replace that with an older version. Before restoring from a backup, make sure you're not currently using any managed objects from the persistent store. Deallocate your NSPersistentContainer
. Unload any UI that makes use of managed objects. Get your app into a state where all it can do is either restore from a backup or go back to using the current data, but where it's not showing any data except the backup list.
Now that you've done that,
- Display the backup list and let the user select one.
- Create an
NSPersistentStoreCoordinator
using your data model. - Use the
replacePersistentStore(at:destinationOptions:withPersistentStoreFrom:sourceOptions:ofType:)
method to copy the backup data to the normal app location. The starting location is the backup location, the destination is where the app normally saves its data. - (optional) Use
NSPersistentStoreCoordinator
's functiondestroyPersistentStore(at:ofType:options:)
to delete the backup. - Load an
NSPersistentContainer
as usual and reload the regular app UI.
Don't use direct file-related APIs like FileManager
for any of this. The Core Data methods will cover all of the Core Data-related files and do other nice things like avoid causing data corruption and respecting file locks.
回答2:
Just my two cents for more valuable thoughts: to tackle the problem, I would try to use CloudKit to create different customer zones to store different backups in the App user’s private database in iCloud from core data.
回答3:
I created the following method with the help of Tom's answer and the Apple sample code. This will take a backup of core data files and place it to the path that you want.
Swift 5
/// Backing up store type to a new and unique location
/// The method is illustrated in the following code fragment, which shows how you can use migratePersistentStore to take a back up of a store and save it from one location to another.
/// If the old store type is XML, the example also converts the store to SQLite.
/// - Parameters:
/// - path: Where you want the backup to be done, please create a new unique directory with timestamp or the guid
/// - completion: Passes error in case of error or pass nil in case of success
class func backUpCoreDataFiles(path : URL, completion : @escaping (_ error : String?) -> ())
{
// Every time new container is a must as migratePersistentStore method will loose the reference to the container on migration
let container = NSPersistentContainer(name : "<YourDataModelName>")
container.loadPersistentStores
{ (storeDescription, error) in
if let error = error
{
fatalError("Failed to load store: \(error)")
}
}
let coordinator = container.persistentStoreCoordinator
let store = coordinator.persistentStores[0]
do
{
try coordinator.migratePersistentStore(store, to : path, options : nil, withType : NSSQLiteStoreType)
completion(nil)
}
catch
{
completion("\(Errors.coredataBackupError)\(error.localizedDescription)")
}
}
来源:https://stackoverflow.com/questions/48613271/backup-core-data-locally-and-restore-from-backup-swift