Ios CloudKit modifyRecordsCompletionBlock随机失败
此应用程序使用CloudKit在本地设备上存储记录和核心数据。本地创建的记录保存到核心数据中。调用以下方法将本地创建的记录发送到CloudKit。当应用程序启动和从后台返回时,我调用此方法。我还为测试阶段编程了一个按钮,它调用这个方法 这种行为似乎完全是随机的。例如,如果我创建了10条记录,其中一些记录被正确上传到CloudKit,而另一些记录则失败。如果我手动重新运行该方法,最终它们都会上传到CloudKit。我一直无法确定成功或失败的模式。在这一点上,我从一个方法中种子测试记录,该方法使记录除了recordName(UUID)和文本字段的后缀之外都是相同的 在有限的测试中,如果我只创建一个记录,它总是有效的 如果我只创造了两个记录,那就是偶尔的失败 如果我创造了五个记录,几乎总是有一个失败 在modifyRecordsCompletionBlock中,无论上载是否成功,updateSavedToCloudKitSuccess()和CleanupMPFile()始终正确完成 我还试着增加超时时间,这完全没有什么区别 任何指导都将不胜感激。Xcode 8.3.3 iOS10 Swift 3Ios CloudKit modifyRecordsCompletionBlock随机失败,ios,swift,cloudkit,Ios,Swift,Cloudkit,此应用程序使用CloudKit在本地设备上存储记录和核心数据。本地创建的记录保存到核心数据中。调用以下方法将本地创建的记录发送到CloudKit。当应用程序启动和从后台返回时,我调用此方法。我还为测试阶段编程了一个按钮,它调用这个方法 这种行为似乎完全是随机的。例如,如果我创建了10条记录,其中一些记录被正确上传到CloudKit,而另一些记录则失败。如果我手动重新运行该方法,最终它们都会上传到CloudKit。我一直无法确定成功或失败的模式。在这一点上,我从一个方法中种子测试记录,该方法使记录
func saveNewCloudKitRecordFromCoreData( myRecordName : String ) {
//get the Core Data record
let patient = findPatientRecord(myRecordName: myRecordName)
privateDatabase = container().privateCloudDatabase
sharedDatabase = sharedContainer().sharedCloudDatabase
recordZone = CKRecordZone(zoneName: "myPatientZone")
let myRecordID : CKRecordID = CKRecordID(recordName: myRecordName, zoneID: (recordZone?.zoneID)!)
let myRecord = CKRecord(recordType: "Patient", recordID : myRecordID)
myRecord.setObject(myRecordName as CKRecordValue?, forKey: "myRecordName")
myRecord.setObject(patient.firstName as CKRecordValue?, forKey: "firstname")
//bunch more fields...
let modifyRecordsOperation = CKModifyRecordsOperation(recordsToSave: [myRecord], recordIDsToDelete: nil)
modifyRecordsOperation.timeoutIntervalForRequest = 10
modifyRecordsOperation.timeoutIntervalForResource = 10
modifyRecordsOperation.modifyRecordsCompletionBlock = {
records, recordIDs, error in
if let err = error {
print("error in modifyRecordsOperation \(err.localizedDescription)")
self.updateSavedToCloudKitSuccess(recordName: myRecordName, success: false)
self.cleanUpTmpFile()
} else {
print("success in modifyRecordsOperation")
self.currentRecord = myRecord
self.updateSavedToCloudKitSuccess(recordName: myRecordName, success: true)
self.cleanUpTmpFile()
}//if err
}//modifyRecordsOperation
privateDatabase?.add(modifyRecordsOperation)
}//saveNewCloudKitRecordFromCoreData
控制台输出示例:
结果:计数为:7
修改记录操作的成功
savedToCloudKit=true
ModifyRecords操作中出错无法修改某些记录
savedToCloudKit=false
ModifyRecords操作中出错无法修改某些记录
savedToCloudKit=false
ModifyRecords操作中出错无法修改某些记录
savedToCloudKit=false
ModifyRecords操作中出错无法修改某些记录
savedToCloudKit=false
修改记录操作的成功
savedToCloudKit=true
修改记录操作的成功
savedToCloudKit=true
根据rmaddy和paulw11的评论,我实现了perRecordCompletionBlock,发现错误总是与CKAsset文件相关。我将查看是否在执行完成块之前清理该临时文件
perRecordCompletionBlock:“;
dateCreated=“2017-08-21 22:20:25+0000”;
出生日期=“2017-04-23 22:20:25+0000”;
firstname=FirstName12;
lastname=ZLastName12;
myRecordName=“7621A7BD-7D32-4984-8117-2189D6F40D5F”;
notes=“这是注释编号12”;
patientlistparent=“”;
初级医师=“Who12博士”;
ssan=123456789;
},recordType=Patient>。错误:可选()
ModifyRecords操作中出错无法修改某些记录
savedToCloudKit=false我通过将资产保存操作放在同步全局队列中解决了这个问题
DispatchQueue.global(qos: .userInitiated).sync {
let tmpDir = NSTemporaryDirectory()
let tmpFile = tmpDir.appending("test.png")
let tmpFileURL = URL(fileURLWithPath: tmpFile)
var asset : CKAsset?
if patient.conditionImage != nil {
let data = NSData(data: patient.conditionImage as! Data) as NSData
do {
try data.write(to: tmpFileURL, options: .atomic)
} catch {
print(error)
}//do catch
asset = CKAsset(fileURL: tmpFileURL)
}//if there is a conditionImage
myRecord.setObject(asset as CKRecordValue?, forKey: "conditionImage")
DispatchQueue.main.async {
//back on main
}//
}//DispatchQueue.global
我通过将资产保存操作放在同步全局队列中解决了这个问题
DispatchQueue.global(qos: .userInitiated).sync {
let tmpDir = NSTemporaryDirectory()
let tmpFile = tmpDir.appending("test.png")
let tmpFileURL = URL(fileURLWithPath: tmpFile)
var asset : CKAsset?
if patient.conditionImage != nil {
let data = NSData(data: patient.conditionImage as! Data) as NSData
do {
try data.write(to: tmpFileURL, options: .atomic)
} catch {
print(error)
}//do catch
asset = CKAsset(fileURL: tmpFileURL)
}//if there is a conditionImage
myRecord.setObject(asset as CKRecordValue?, forKey: "conditionImage")
DispatchQueue.main.async {
//back on main
}//
}//DispatchQueue.global
看看个别的部分错误。正如rmaddy所说,看看个别错误;要做到这一点,请在“bunch more fields”中实现您是否有一个CKAsset?我确实有一个CKAsset,但是在测试过程中,它总是同一个图像,并且相对较小(小于200kB)。我将实现每记录完成块以查看错误-我没有看到。谢谢。您不需要“每记录”“完成区块。您应该在表示错误代码
partialFailure
的最终完成块中得到一个错误。这将包含失败记录的记录ID上的错误键字典。Paulw11,Maddy-你搞定了。CKAsset字段存在一些问题。我确实实现了按记录完成块,所有的错误都是查找资产文件的错误。我必须有一些问题,在完成之前删除该文件。我会弄明白并发布。在此期间,我将编辑我的文章与错误的情况下,其他人有这个问题。为了让grins知道,我注释掉了上传CKAsset的行,并用50条记录运行了一个测试——没有错误。谢谢。看看个别的部分错误。正如rmaddy所说,看看个别错误;要做到这一点,请在“bunch more fields”中实现您是否有一个CKAsset?我确实有一个CKAsset,但是在测试过程中,它始终是相同的图像,并且相对较小(小于200kB)。我将实现每记录完成块来查看错误-我没有看到这一点。谢谢。你不需要“每记录”完成块。您应该在表示错误代码partialFailure
的最终完成块中得到一个错误。这将包含失败记录的记录ID上的错误键字典。Paulw11,Maddy-你搞定了。CKAsset字段存在一些问题。我确实实现了按记录完成块,所有的错误都是查找资产文件的错误。我必须有一些问题,在完成之前删除该文件。我会弄明白并发布。在此期间,我将编辑我的文章与错误的情况下,其他人有这个问题。为了让grins知道,我注释掉了上传CKAsset的行,并用50条记录运行了一个测试——没有错误。谢谢