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.
I've never needed to do this but if I did this is what I'd do.
At any time, use the following steps:
NSPersistentContainer
or the older (but still supported) method of creating an NSPersistentStoreCoordinator
.NSPersistentStoreCoordinator
's function migratePersistentStore(_: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.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.
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,
NSPersistentStoreCoordinator
using your data model.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.NSPersistentStoreCoordinator
's function destroyPersistentStore(at:ofType:options:)
to delete the backup.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.
Update: I later wrote a blog post that covers this in more detail, with sample code: https://atomicbird.com/blog/core-data-back-up-store/
func backup(backupName: String){
let backUpFolderUrl = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!
let backupUrl = backUpFolderUrl.appendingPathComponent(backupName + ".sqlite")
let container = NSPersistentContainer(name: "Your Project Name")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in })
let store:NSPersistentStore
store = container.persistentStoreCoordinator.persistentStores.last!
do {
try container.persistentStoreCoordinator.migratePersistentStore(store,to: backupUrl,options: nil,withType: NSSQLiteStoreType)
} catch {
print("Failed to migrate")
}
}
That's it!
Now,
func restoreFromStore(backupName: String){
print(DatabaseHelper.shareInstance.getAllUsers())
let storeFolderUrl = FileManager.default.urls(for: .applicationSupportDirectory, in:.userDomainMask).first!
let storeUrl = storeFolderUrl.appendingPathComponent("YourProjectName.sqlite")
let backUpFolderUrl = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!
let backupUrl = backUpFolderUrl.appendingPathComponent(backupName + ".sqlite")
let container = NSPersistentContainer(name: "YourProjectName")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
let stores = container.persistentStoreCoordinator.persistentStores
for store in stores {
print(store)
print(container)
}
do{
try container.persistentStoreCoordinator.replacePersistentStore(at: storeUrl,destinationOptions: nil,withPersistentStoreFrom: backupUrl,sourceOptions: nil,ofType: NSSQLiteStoreType)
print(DatabaseHelper.shareInstance.getAllUsers())
} catch {
print("Failed to restore")
}
})
}
self.backup(backupName: "first_backup")
self.restoreFromStore(backupName: "first_backup")
That's it.. Hope this helpful. Thank You
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With