【发布时间】:2018-07-14 18:14:50
【问题描述】:
我正在努力寻找有关创建核心数据备份的任何信息。我的最终目标是允许用户创建多个备份,并从选定的备份中恢复。
我找到了一个示例项目,它允许您在 Objective-C 中本地或通过 iCloud 进行备份/恢复,但在 swift 中没有。
有人可以帮忙吗?或者指出我正确的方向。我什至不知道从哪里开始。
【问题讨论】:
标签: ios swift core-data backup restore
我正在努力寻找有关创建核心数据备份的任何信息。我的最终目标是允许用户创建多个备份,并从选定的备份中恢复。
我找到了一个示例项目,它允许您在 Objective-C 中本地或通过 iCloud 进行备份/恢复,但在 swift 中没有。
有人可以帮忙吗?或者指出我正确的方向。我什至不知道从哪里开始。
【问题讨论】:
标签: ios swift core-data backup restore
我从来不需要这样做,但如果我这样做了,我就会这样做。
在任何时候,使用以下步骤:
NSPersistentContainer 或旧的(但仍受支持)方法来创建NSPersistentStoreCoordinator。NSPersistentStoreCoordinator的函数migratePersistentStore(_:to:options:withType:)创建备份。使用 UUID 或时间戳使目标 URL 包含唯一的内容。将备份放在文档文件夹中。UserDefaults 或创建一个新的属性列表文件以保存备份信息。步骤 #2 将从 Core Data 堆栈中删除原始存储 - 这就是您在步骤 #1 中创建第二个堆栈的原因。这样,您可以使用第二个堆栈进行备份,而不会影响您的应用正在使用的堆栈。
如果您使用的是NSPersistentContainer,请使用其persistentStoreCoordinator 属性来执行步骤#2。
这有点棘手,因为您的应用可能正在使用其持久存储,但现在您想用旧版本替换它。 在从备份恢复之前,请确保您当前没有使用持久存储中的任何托管对象。 取消分配您的 NSPersistentContainer。卸载任何使用托管对象的 UI。让您的应用进入一种状态,它所能做的就是从备份中恢复或返回使用当前数据,但除了备份列表之外不显示任何数据。
既然你已经这样做了,
NSPersistentStoreCoordinator。replacePersistentStore(at:destinationOptions:withPersistentStoreFrom:sourceOptions:ofType:)方法将备份数据复制到正常的应用位置。起始位置是备份位置,目标位置是应用通常保存其数据的位置。NSPersistentStoreCoordinator的函数destroyPersistentStore(at:ofType:options:)删除备份。NSPersistentContainer 并重新加载常规应用 UI。不要使用直接与文件相关的 API,例如 FileManager。 Core Data 方法将涵盖所有与 Core Data 相关的文件,并做其他好事,例如避免导致数据损坏和遵守文件锁定。
更新:我后来写了一篇博文,更详细地介绍了这一点,并附有示例代码: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")
}
}
就是这样!
现在,
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")
就是这样..希望这有帮助。谢谢你
【讨论】:
我在 Tom 的回答和 Apple 示例 code 的帮助下创建了以下方法。 这将备份核心数据文件并将其放置到您想要的路径。
斯威夫特 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)")
}
}
【讨论】:
我的两分钱更有价值的想法:为了解决这个问题,我会尝试使用 CloudKit 创建不同的客户区域,以将来自核心数据的应用用户私有数据库中的不同备份存储在 iCloud 中。
【讨论】: