强制 NSPersistentContainer 更改核心数据

ap1*_*123 7 xcode core-data icloud swift nspersistentcloudkitcontainer

我刚刚添加了一个选项,供用户在我的应用程序中切换云同步,我保存用户是否要在“useCloudSync”下的 UserDefaults 中使用 iCloud 同步。当应用程序运行时,我加载我的persistentContainer:

class CoreDataManager {
    static let sharedManager = CoreDataManager()
    private init() {}

    lazy var persistentContainer: NSPersistentContainer = {
        var useCloudSync = UserDefaults.standard.bool(forKey: "useCloudSync")

        let containerToUse: NSPersistentContainer?
        if useCloudSync {
           containerToUse = NSPersistentCloudKitContainer(name: "App")
        } else {
            containerToUse = NSPersistentContainer(name: "App")
            let description = containerToUse!.persistentStoreDescriptions.first
            description?.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
      }

        guard let container = containerToUse, let description = container.persistentStoreDescriptions.first else {
            fatalError("Hey Listen! ###\(#function): Failed to retrieve a persistent store description.")
        }
        description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)

        container.loadPersistentStores(completionHandler: { (storeDescription, error) in

      ...

      return container
   }
}
Run Code Online (Sandbox Code Playgroud)

当用户使用 UISwitcher 切换云同步时,我更改了 UserDefaults 中“useCloudSyc”的值,但应用程序不会使用 ,NSPersistentCloudKitContainer直到他们强制关闭应用程序并再次重新运行它。我希望容器在用户切换开关以开始从 iCloud 加载数据时正确更改。

NSPersistentCloudKitContainer当用户切换“CloudSync”时,我如何在 a 和 a 之间切换?

Asp*_*eri 6

Here is possible approach

extension UserDefaults { // helper key path for observing
    @objc dynamic var useCloudSync: Bool {
        return bool(forKey: "useCloudSync")
    }
}

class CoreDataManager {
    static let sharedManager = CoreDataManager()

    private var observer: NSKeyValueObservation?
    private init() {
    }

    lazy var persistentContainer: NSPersistentContainer = {
        setupContainer()
    }()

    private func setupContainer() -> NSPersistentContainer {

        if nil == observer {
            // setup observe for defults changed
            observer = UserDefaults.standard.observe(\.useCloudSync) { [weak self] (_, _) in
                try? self?.persistentContainer.viewContext.save() // save anything pending
                if let newContainer = self?.setupContainer() {
                    self?.persistentContainer = newContainer
                }
            }
        }

        let useCloudSync = UserDefaults.standard.bool(forKey: "useCloudSync")

        let containerToUse: NSPersistentContainer?
        if useCloudSync {
            containerToUse = NSPersistentCloudKitContainer(name: "App")
        } else {
            containerToUse = NSPersistentContainer(name: "App")
            let description = containerToUse!.persistentStoreDescriptions.first
            description?.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
        }

        guard let container = containerToUse, let description = container.persistentStoreDescriptions.first else {
            fatalError("Hey Listen! ###\(#function): Failed to retrieve a persistent store description.")
        }
        description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)

        container.loadPersistentStores { (storeDescription, error) in
            //      ...
        }

        return container
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你好,我刚刚发现了一个以前没有见过的错误。当切换持久容器时,我对核心数据数据库中的每个项目都会收到此错误:“CoreData:警告:多个 NSEntityDescriptions 声明 NSManagedObject 子类“App.Item”,因此 +entity 无法消除歧义。” 其中 app 是我的应用程序的名称,item 是实体类型之一。我相信发生这种情况是因为旧容器在切换后仍然打开。有没有一种方法可以在使用新的持久容器之前关闭旧的持久容器,也许上面的 `self?.persistentContainer = newContainer` 之上? (2认同)