Cloudkit 共享更新核心数据 NSManaged 对象

我有一个简单的购物清单应用程序,它在 Cloudkit 中使用 Core Data。用户创建一个列表,然后将项目添加到列表中。该列表可以共享给其他用户。 Core Data 首先用于将 Lists 和 Items 保存为 NSManaged Objects。然后将列表共享给可以将项目添加到列表的另一个用户,并且在同一列表上工作的两个用户彼此保持同步。这大部分都在工作,但我在获取 Core Data 以使用 Cloud Kit Share 中的更改更新本地存储的 NSManaged 对象时遇到了一些麻烦。

目前,该应用程序正在处理 NSManaged Objects 和 CKRecords 的混合,以显示在显示列表中项目的表视图中。这有点乱。我真的很想使用 Cloudkit 来处理 NSManaged Objects,从而在 2 个用户之间保持同步。

当用户 B 添加一个项目时,它成功地保存到共享数据库并将父项设置为共享列表。这是我有点卡住的地方,因为我希望用户 A 看到用户 B 添加的项目,并且我想使用 CloudKit 在后台创建的 NSManaged 对象来更新 UI。

在后台 Cloudkit 看到用户 B 添加到共享数据库中的新 CKRecord 并为用户 A 创建一个新的 NSManaged 对象。当应用程序转到 Cloudkit 时,我只能获取核心数据来保存新的 NSManaged Object Cloudkit后台或关闭然后重新启动。我确实等待了大约一分钟以确保同步发生。检查用户 A 的 Sqlite 数据库,用户 B 添加的新项目不在那里。当应用程序进入后台并且我再次检查 Sqlite 数据库时,然后添加了项目。看起来 Cloudkit 制作的 NSManaged 对象只有在应用进入后台时才会保存到 Core Data 中。

长话短说,有没有办法让 Core Data 保存 CloudKit 创建的 NSManaged 对象,而无需应用程序进入后台?

这是我设置容器的代码,我确实有设置远程通知和推送通知的权利。此外 (application.registerForRemoteNotifications()) 在 App 委托中设置。我在这里遗漏了什么吗?

 lazy var persistentContainer: NSPersistentCloudKitContainer = {

    let container = NSPersistentCloudKitContainer(name: "Shopping_List")
    
    let description = container.persistentStoreDescriptions.first
            description?.setOption(true as Nsnumber,forKey: NSPersistentHistoryTrackingKey)
    
    // listen for remote notifications
    let remoteChangeKey = "NSPersistentStoreRemoteChangeNotificationOptionKey"
    
       description?.setOption(true as Nsnumber,forKey: remoteChangeKey)

 
    container.loadPersistentStores(completionHandler: { (storeDescription,error) in
        if let error = error as NSError? {

            fatalError("Unresolved error \(error),\(error.userInfo)")
        }
   
    })
    
    
    container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    
    
    container.viewContext.automaticallyMergesChangesFromParent = true
    
 
    
    return container
    
}()

这是在共享数据库中添加新项目的代码

  let saveaction = UIAlertaction(title: "Add",style: .default) { [self] (alert) in
   
               if itemNameTextField.text != "" || itemNameTextField.text != nil {
                
   
                 //CLOUD KIT ADD ITEM - IF LIST IS A CKRECORD IT IS SHARED FROM CLOUD KIT. CREATE A NEW ITEM AS A CKRECORD SAVE TO SHARE
                
                let ckRecord = selectedList as? CKRecord
                
                if ckRecord != nil {
         
                 // get the parent record ID as a string.  Used to set the CD_Parent List property of the new record
                    let parentListId = ckRecord!.recordID.recordName
                    
                 // create a new record ID using the selected list's record zone ID.  Need this to create the new record setting its Zone ID the same as the parent.
                    
                    let newItemID = CKRecord.ID(zoneID: ckRecord!.recordID.zoneID)
                    
                    // create new CKRecord,setting the Type of record
                    
                    let ckNewItem = CKRecord(recordType: "CD_Item",recordID: newItemID)
                    
                    
                    
                    // set the a value for a key.  The value has to be downcast as a CKRecord Value.  The value must also match the datatype that has been set for key.  Check the Core Data to see which attributes(keys) have which data types.  Attirbute names are all the same only difference is for cloud kit it has "CD_" prefixed.
                    
                    ckNewItem.setObject(itemNameTextField.text as CKRecordValue?,forKey: "CD_itemName")
                    
                    // get the string value as a Int 64 number from the text field.  The number of items attribute is an Integer not string.
                    let number = Int64(numberOfItemsTextField.text ?? "1") ?? 1
                    
                    ckNewItem.setObject(number as CKRecordValue,forKey: "CD_numberOfItems")
                    
                    ckNewItem.setObject(false as CKRecordValue,forKey: "CD_done")
                    
                    ckNewItem.setObject(parentListId as CKRecordValue,forKey: "CD_parentList")
                    
                    ckNewItem.setObject("Item" as CKRecordValue,forKey: "CD_entityName")
                    
                   
                    
                    // set the parent as the selected list - create a CK reference based on the selected list
                    
                    ckNewItem.parent = CKRecord.Reference(record: ckRecord!,action: .none)
                    
                    // save the newCKRecord to the shared Database
                    
                    container.saveRecord(ckNewItem,on: container.sharedCloudDatabase) { (record,error) in
                        
                        if error != nil {
                            
                            //show error to user.
                            
                            print ("Error Saving Record")
                        }
                        
                        if let safeRecord = record {
                            
                            self.loadedItems.append(safeRecord)
                            
                            DispatchQueue.main.async {
                                
                                tableView.reloadData()
                            }
                            
                        }
                       
                    }
                  
                }
                

            }
   
        }
southwesting1228 回答:Cloudkit 共享更新核心数据 NSManaged 对象

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/525163.html

大家都在问