Ios 本地备份核心数据,并从备份中恢复-Swift

Ios 本地备份核心数据,并从备份中恢复-Swift,ios,swift,core-data,backup,restore,Ios,Swift,Core Data,Backup,Restore,我正在努力寻找有关创建核心数据备份的任何信息。我的最终目标是允许用户创建多个备份,并从选定的备份进行恢复 我发现了一个示例项目,它允许您在Objective-C中本地或通过iCloud进行备份/恢复,但在swift中没有 有人能帮忙吗?或者给我指出正确的方向。我甚至不知道从哪里开始 我只需花两分钱就可以得到更多有价值的想法:为了解决这个问题,我会尝试使用CloudKit创建不同的客户区域,在iCloud中的应用程序用户的私有数据库中存储来自核心数据的不同备份。我从来都不需要这样做,但如果我这样做

我正在努力寻找有关创建核心数据备份的任何信息。我的最终目标是允许用户创建多个备份,并从选定的备份进行恢复

我发现了一个示例项目,它允许您在Objective-C中本地或通过iCloud进行备份/恢复,但在swift中没有


有人能帮忙吗?或者给我指出正确的方向。我甚至不知道从哪里开始

我只需花两分钱就可以得到更多有价值的想法:为了解决这个问题,我会尝试使用CloudKit创建不同的客户区域,在iCloud中的应用程序用户的私有数据库中存储来自核心数据的不同备份。

我从来都不需要这样做,但如果我这样做了,我会这么做

备份 在任何时候,请使用以下步骤:

  • 创建新的第二个核心数据堆栈。使用
    NSPersistentContainer
    或创建
    NSPersistentStoreCoordinator
    的旧方法(但仍受支持)
  • 使用NSPersistentStoreCoordinator的函数来创建备份。使用UUID或时间戳使目标URL包含唯一的内容。将备份放在documents文件夹中
  • 按日期保留备份列表。您可以将其放入
    UserDefaults
    或创建新的属性列表文件以保存备份信息
  • 步骤2将从核心数据堆栈中删除原始存储——这就是为什么在步骤1中创建第二个堆栈。这样,您就可以使用第二个堆栈进行备份,而不会影响应用程序正在使用的堆栈

    如果您使用的是
    NSPersistentContainer
    ,请使用其
    persistentStoreCoordinator
    属性执行步骤2

    从备份中恢复 这有点棘手,因为您的应用程序可能正在使用其持久存储,但现在您想用旧版本替换它从备份还原之前,请确保当前未使用永久存储中的任何托管对象。解除分配您的
    nspersistentcainer
    。卸载使用托管对象的任何UI。让你的应用进入这样一种状态:它所能做的就是从备份中恢复,或者返回到使用当前数据的状态,但是除了备份列表之外,它不会显示任何数据

    既然你这么做了

  • 显示备份列表并让用户选择一个
  • 使用数据模型创建一个
    NSPersistentStoreCoordinator
  • 使用
    replacePersistentStore(at:destinationOptions:withPersistentStoreFrom:sourceOptions:ofType:)
    方法将备份数据复制到正常的应用程序位置。起始位置是备份位置,目标位置是应用程序通常保存其数据的位置
  • (可选)使用
    NSPersistentStoreCoordinator
    的函数
    destroyPersistentStore(位于:ofType:options:)
    删除备份
  • 像往常一样加载
    NSPersistentContainer
    ,然后重新加载常规应用程序UI
  • 不要使用直接与文件相关的API,如
    FileManager
    ,来实现这些功能。核心数据方法将覆盖所有与核心数据相关的文件,并做其他好事,如避免造成数据损坏和遵守文件锁


    更新:我后来写了一篇博客文章,详细介绍了这一点,并给出了示例代码:

    我在Tom的答案和苹果示例的帮助下创建了以下方法。 这将备份核心数据文件,并将其放置到所需的路径

    斯威夫特5

    ///将存储类型备份到新的唯一位置
    ///下面的代码片段演示了该方法,其中显示了如何使用migratePersistentStore备份存储并将其从一个位置保存到另一个位置。
    ///如果旧的存储类型是XML,则示例还将该存储转换为SQLite。
    ///-参数:
    ///-路径:要在其中完成备份,请创建一个带有时间戳或guid的新唯一目录
    ///-完成:出错时通过错误,成功时通过零
    类func backUpCoreDataFiles(路径:URL,完成:@escaping(u错误:String?)->())
    {
    //每次必须创建新容器时,migratePersistentStore方法都会在迁移时丢失对容器的引用
    let container=NSPersistentContainer(名称:“”)
    container.loadPersistentStores
    中的{(storeDescription,错误)
    如果let error=error
    {
    fatalError(“未能加载存储:\(错误)”)
    }
    }
    let coordinator=container.persistentStoreCoordinator
    let store=coordinator.persistentStores[0]
    做
    {
    尝试coordinator.migratePersistentStore(store,to:path,options:nil,withType:NSSQLiteStoreType)
    完成(无)
    }
    抓住
    {
    完成(\(Errors.coredataBackupError)\(error.localizedDescription))
    }
    }
    
    详细信息
    • Swift 5.1,Xcode 11.3.1
    核心数据备份 就这样

    现在,

    核心数据恢复 用法
    就这样。。希望这有帮助。谢谢你的建议。对我的应用程序来说,这一过程完全离线并且不依赖于CloudKit或iCloud是很重要的。所以我真的需要在本地存储。我相信这只是复制SQLLite文件并保存到位置的一个例子。恢复。抄回。但我不知道如何做到这一点。我没有离线备份的经验,但会研究将数据编码到本地文件并压缩文件,以间接满足您的目的,并使用Swift。为了直接备份和恢复SQLLite文件,我会查看标准库,但对Swift I的任何发现表示怀疑
        /// 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)")
                }
            }
    
     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")