如何保存到核心数据中的特定存储/配置

问题描述 投票:0回答:1

我目前正在将核心数据与

CloudKit
private
public
数据库同步,正如您在下面的代码中看到的,我将
private
数据库保存在 Core Data 中的
default
配置中,并且名为
public
的配置中的
Public
NSPersistentCloudKitContainer
同步时一切正常,我遇到的问题是尝试保存到公共数据存储
PublicStore
,例如当我尝试使用
 保存时func createIconImage(imageName: String)
它将图像保存到“默认”存储,而不是
PublicStore
Public
配置)。

我该怎么做才能将

createIconImage()
函数保存到
PublicStore
sqlite 数据库?

    class CoreDataManager: ObservableObject{
        static let instance = CoreDataManager()
        private let queue = DispatchQueue(label: "CoreDataManagerQueue")
        
        @AppStorage(UserDefaults.Keys.iCloudSyncKey) private var iCloudSync = false
        
        lazy var context: NSManagedObjectContext = {
        return container.viewContext
        }()
        
        lazy var container: NSPersistentContainer = {
        return setupContainer()
        }()
        
        init(inMemory: Bool = false){
            if inMemory {
                container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
            }
        }
        
        func updateCloudKitContainer() {
            queue.sync {
                container = setupContainer()
            }
        }

        private func getDocumentsDirectory() -> URL {
            return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        }

        private func getStoreURL(for storeName: String) -> URL {
            return getDocumentsDirectory().appendingPathComponent("\(storeName).sqlite")
        }
        
        func setupContainer()->NSPersistentContainer{
            let container = NSPersistentCloudKitContainer(name: "CoreDataContainer")
            let cloudKitContainerIdentifier = "iCloud.com.example.MyAppName"
            
            guard let description = container.persistentStoreDescriptions.first else{
                fatalError("###\(#function): Failed to retrieve a persistent store description.")
            }
            
            description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
            description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
            
            if iCloudSync{
                if description.cloudKitContainerOptions == nil {
                    let options = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudKitContainerIdentifier)
                    description.cloudKitContainerOptions = options
                }
            }else{
                print("Turning iCloud Sync OFF... ")
                description.cloudKitContainerOptions = nil
            }
            
            // Setup public database
            let publicDescription = NSPersistentStoreDescription(url: getStoreURL(for: "PublicStore"))
            publicDescription.configuration = "Public" // this is the configuration name
            if publicDescription.cloudKitContainerOptions == nil {
                let publicOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudKitContainerIdentifier)
                publicOptions.databaseScope = .public
                publicDescription.cloudKitContainerOptions = publicOptions
            }
            container.persistentStoreDescriptions.append(publicDescription)
            
            container.loadPersistentStores { (description, error) in
                if let error = error{
                    print("Error loading Core Data. \(error)")
                }
            }
            container.viewContext.automaticallyMergesChangesFromParent = true
            container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

            return container
        }
        
        func save(){
            do{
                try context.save()
                //print("Saved successfully!")
            }catch let error{
                print("Error saving Core Data. \(error.localizedDescription)")
            }
        }
    }


    class PublicViewModel: ObservableObject {
        let manager: CoreDataManager
        
        @Published var publicIcons: [PublicServiceIconImage] = []
        
        init(coreDataManager: CoreDataManager = .instance) {
            self.manager = coreDataManager
        }

        func createIconImage(imageName: String) {
            let newImage = PublicServiceIconImage(context: manager.context)

            newImage.imageName = imageName
            newImage.id = UUID()
            
            save()
        }
        
        func save() {
            self.manager.save()
        }
    }
swift core-data cloudkit
1个回答
0
投票

经过几天的尝试不同的事情,我意外地发现容器数组中的描述顺序对于 Core Data 如何优先加载配置和保存实体起着至关重要的作用。在我的原始代码中,我首先加载默认配置,如下所示......

 guard let description = container.persistentStoreDescriptions.first else{
      fatalError("###\(#function): Failed to retrieve a persistent store description.")
  }

然后我附加公共配置如下......

container.persistentStoreDescriptions.append(publicDescription)

将公共配置保留在 persistenceStoreDescriptions 数组的末尾,显然,Core Data 的工作方式是搜索第一个配置,如果您要保存的实体存在于第一个配置中,则将其保存在该配置中,否则它不断循环遍历所有配置,直到找到其中一个配置中的实体,但由于(默认情况下)

Default
配置包含所有实体,因此它始终保存到默认配置,因此解决方案是始终保留默认配置作为数组中的最后一项。

这是我解决问题的方法:

替换了这条线...

container.persistentStoreDescriptions.append(publicDescription)

与...

container.persistentStoreDescriptions = [publicDescription, description]

再次,我基本上将公共配置添加到数组中的第一个配置中。这里的关键是最后始终保留默认配置,无论您有多少配置。

© www.soinside.com 2019 - 2024. All rights reserved.