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

时间:2018-02-04 21:40:55

标签: ios swift core-data backup restore

我很难找到有关创建核心数据备份的任何信息。我的最终目标是允许用户创建多个备份,并从选定的备份进行还原。

我找到了一个示例项目,允许您在本地或通过Objective-C中的iCloud进行备份/恢复,但没有什么在swift中。

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

4 个答案:

答案 0 :(得分:15)

我从来不需要这样做,但如果我这样做,那就是我要做的事。

进行备份

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

  1. 创建新的第二个核心数据堆栈。使用InputDecoration或较旧(但仍受支持)的方法创建NSPersistentContainer
  2. 使用NSPersistentStoreCoordinator的函数NSPersistentStoreCoordinator创建备份。使用UUID或时间戳使目标URL包含唯一的内容。将备份放在文档文件夹中。
  3. 按日期保留备份列表。您可以将其放在migratePersistentStore(_:to:options:withType:)中或创建新的属性列表文件以保存备份信息。
  4. 步骤#2将从Core Data堆栈中删除原始存储 - 这就是您在步骤#1中创建第二个堆栈的原因。这样,您可以使用第二个堆栈进行备份,而不会影响您的应用正在使用的备份。

    如果您使用的是UserDefaults,请使用其NSPersistentContainer属性执行第2步。

    从备份恢复

    这有点棘手,因为您的应用可能正在使用其持久性存储,但现在您想用旧版本替换它。 从备份恢复之前,请确保您当前没有使用持久存储中的任何托管对象。取消分配您的persistentStoreCoordinator。卸载任何使用托管对象的UI。让您的应用程序进入一种状态,它可以做的就是从备份恢复或返回使用当前数据,但除了备份列表之外它没有显示任何数据。

    现在你已经完成了,

    1. 显示备份列表,让用户选择一个。
    2. 使用您的数据模型创建NSPersistentContainer
    3. 使用NSPersistentStoreCoordinator方法将备份数据复制到普通的应用位置。起始位置是备份位置,目标是应用程序通常保存其数据的位置。
    4. (可选)使用replacePersistentStore(at:destinationOptions:withPersistentStoreFrom:sourceOptions:ofType:)的函数NSPersistentStoreCoordinator删除备份。
    5. 像往常一样加载destroyPersistentStore(at:ofType:options:)并重新加载常规应用UI。
    6. 不要将NSPersistentContainer之类的直接文件相关API用于此任何一项。核心数据方法将涵盖所有与核心数据相关的文件,并做其他好事,例如避免导致数据损坏和尊重文件锁。

答案 1 :(得分:3)

详细信息

  • Swift 5.1,Xcode 11.3.1

核心数据备份

yourhost/api/-default-/public/alfresco/versions/1/nodes/{{uiid}

就是这样!

现在

核心数据还原

 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")
            }

        })

    }

就是这样。希望这对您有所帮助。谢谢

答案 2 :(得分:0)

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

答案 3 :(得分:0)

我在汤姆的答案和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)")
            }
        }