我一直在测试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 <CKRecordID: 0x144684a80; basicRecord:(_defaultZone:__defaultOwner__)> to server: (null)"; uuid = 182C497F-966C-418A-9E6A-5563BA6CC6CD; container ID = "iCloud.com.yourcompany.CloudKit">
答案 0 :(得分:12)
此错误可能是因为saveRecord:
仅适用于比服务器上的版本更新的新记录或记录:
此方法仅在以前从未保存过记录或者如果它比服务器上的版本更新时保存记录。您无法使用此方法覆盖服务器上记录的较新版本。 CKDatabase docs
修改现有记录(或记录集)的建议方法是使用带有所需CKModifyRecordsOperation
的{{1}}集来处理冲突:
修改记录的字段后,使用此类操作对象将这些更改保存到数据库。 (......) 保存记录时,savePolicy属性中的值确定在服务器上检测到冲突时如何继续。 CKModifyRecordsOperation docs
答案 1 :(得分:1)
来自CKRecord的文档:
新记录仅存在于内存中,直到您将它们明确保存到iCloud。
设置新值[record setValue:@"newValue" forKey:@"defaultKey"];
时,您已保存记录,使其无效。
您可以使用CKModifyRecordsOperation
,在大多数情况下,它可能更适合您,但您不必这样做。只需使用全新的CKRecord
获取您的数据,然后按照here所述将该记录投放到saveRecord:
。
答案 2 :(得分:0)
保存记录后,获取它以便后面的记录将具有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)
}
}