【问题标题】:Forcing NSPersistentContainer change Core Data强制 NSPersistentContainer 更改核心数据
【发布时间】:2020-07-16 10:01:12
【问题描述】:

我刚刚为用户添加了在我的应用程序中切换云同步的选项,我保存了用户是否要在“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
   }
}

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

当用户切换“CloudSync”时,我如何更改NSPersistentCloudKitContainer

【问题讨论】:

    标签: swift xcode core-data icloud nspersistentcloudkitcontainer


    【解决方案1】:

    这是可能的方法

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

    【讨论】:

    • 这成功了!我唯一注意到的一点是,每当我设置“useCloudSync”时,setupContainer() 会被调用两次。有没有可能解决这个问题?我检查了我是否设置了两次“useCloudSync”,但我没有
    • @ap123,我不能确定,cause I don't have all your code, but you can set breakpoint into first line of setupContainer`,所以你可以捕捉到第一次和第二次调用它的来源,从而清楚可能需要一些额外条件的地方.
    • 你好,我刚刚发现了一个我以前没有看到的错误。切换持久性容器时,核心数据数据库中的每个项目都会出现此错误:“CoreData:警告:多个 NSEntityDescriptions 声明 NSManagedObject 子类 'App.Item',因此 +entity 无法消除歧义。”其中 app 是我的应用程序的名称,而 item 是实体类型之一。我相信这是因为旧容器在切换后仍然打开。有没有办法在使用新的持久性容器之前关闭旧的持久性容器,可能在上方 self?.persistentContainer = newContainer 上方的某个地方??
    • 你修好了吗?
    • 这为我解决了问题:stackoverflow.com/a/51857486/8700044
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多