在CloudKit中保存修改后的数据

我一直在测试CloudKit,因为我希望在发布iOS8时使用它来发布应用程序。 使用以下代码保存数据似乎很简单:

CKRecordID * recordID = [[CKRecordID alloc] initWithRecordName:@"basicRecord"]; CKRecord * record = [[CKRecord alloc] initWithRecordType:@"basicRecordType" recordID:recordID]; [record setValue:@"defaultValue" forKey:@"defaultKey"]; CKDatabase *database = [[CKContainer defaultContainer] publicCloudDatabase]; [database saveRecord:record completionHandler:^(CKRecord *record, NSError *error) { if (error) { NSLog(@"Error: %@", error); } else { NSLog(@"Record Saved!"); } }]; 

我没有收到任何错误。 但是,如果我再次尝试运行代码,可能是因为我已将记录值更改为

 [record setValue:@"newValue" forKey:@"defaultKey"]; 

我收到一个错误提出问题,我如何保存修改过的数据。 毕竟,这是将事物保存到云端的基本部分。 错误如下,任何帮助将不胜感激,请不要犹豫,要求进一步的信息。

 Error: <CKError 0x17024afb0: "Server Record Changed" (14/2017); "Error saving record  to server: (null)"; uuid = 182C497F-966C-418A-9E6A-5563BA6CC6CD; container ID = "iCloud.com.yourcompany.CloudKit"> 

此错误可能是因为saveRecord:仅适用于比服务器上的版本更新的新记录或记录:

此方法仅在以前从未保存过记录或者如果它比服务器上的版本更新时保存记录。 您无法使用此方法覆盖服务器上记录的较新版本。 CKDatabase文档

修改现有记录(或记录集)的推荐方法是使用带有所需savePolicy来处理冲突:

修改记录的字段后,使用此类操作对象将这些更改保存到数据库。 (…)保存记录时,savePolicy属性中的值确定在服务器上检测到冲突时如何继续。 CKModifyRecordsOperation docs

来自CKRecord的文档:

新记录仅存在于内存中,直到您将它们明确保存到iCloud。

当你设置新值[record setValue:@"newValue" forKey:@"defaultKey"]; 您已保存记录,使其无效。

您可以使用CKModifyRecordsOperation ,在大多数情况下,它可能是CKModifyRecordsOperation ,但您不必这样做。 只需使用新的CKRecord获取数据,然后将该记录输入saveRecord:如此处所述。

保存记录后,获取它,以便恢复的记录将具有Cloudkit添加的RecordID

然后在同一个提取的记录上,使用setValue更改要更改的数据

然后你可以使用CFModifyRecordsOperation在下面的例子中,cachedCKRecordsServiceCenter包含来自cloudkit的读取记录,那些记录中包含CloudKit RecordID ……

  //find this service center in the cached records for (_,serviceCenter) in (theModel?.cachedCKRecordsServiceCenter.enumerated())! //is data for logged in Co ONLY with NO Co name attached { let name = serviceCenter["name"] as! String returnValue = "Try Again" if name == displayedRecordName { serviceCenter.setValue(displayedRecordName! + "_" + (theModel?.companyName)!, forKey: "name") //db values have Co name appended serviceCenter.setValue(label2Text.text, forKey:"street1") serviceCenter.setValue(label3Text.text, forKey:"street2") serviceCenter.setValue(label4Text.text, forKey:"city") serviceCenter.setValue(label5Text.text, forKey:"state") serviceCenter.setValue(label6Text.text, forKey:"zip") serviceCenter.setValue(label7Text.text, forKey:"phone") serviceCenter.setValue(label8Text.text, forKey:"email") serviceCenter.setValue(label9Text.text, forKey:"note") let saveRecordsOperation = CKModifyRecordsOperation() var ckRecordsArray = [CKRecord]() // set values to ckRecordsArray ckRecordsArray.append(serviceCenter) saveRecordsOperation.recordsToSave = ckRecordsArray saveRecordsOperation.savePolicy = .ifServerRecordUnchanged appDelegate.locked = true saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in if error != nil { // Really important to handle this here ////////print("ERROR: Unable to update Driver Location: Error= \(error)") self.returnValue = "ERROR: Unable to update Driver Location: ERROR = \(error)" self.appDelegate.locked=false } else { ////print("Successfully updated Service Center") self.appDelegate.locked=false self.returnValue = "Successfully updated Service Center" self.appDelegate.locked=false //reget the data into the cach self.theModel?.fetchServiceCenterFromCloudKit1() } } CKContainer.default().publicCloudDatabase.add(saveRecordsOperation) } }