Ios CloudKit modifyRecordsCompletionBlock随机失败

Ios CloudKit modifyRecordsCompletionBlock随机失败,ios,swift,cloudkit,Ios,Swift,Cloudkit,此应用程序使用CloudKit在本地设备上存储记录和核心数据。本地创建的记录保存到核心数据中。调用以下方法将本地创建的记录发送到CloudKit。当应用程序启动和从后台返回时,我调用此方法。我还为测试阶段编程了一个按钮,它调用这个方法 这种行为似乎完全是随机的。例如,如果我创建了10条记录,其中一些记录被正确上传到CloudKit,而另一些记录则失败。如果我手动重新运行该方法,最终它们都会上传到CloudKit。我一直无法确定成功或失败的模式。在这一点上,我从一个方法中种子测试记录,该方法使记录

此应用程序使用CloudKit在本地设备上存储记录和核心数据。本地创建的记录保存到核心数据中。调用以下方法将本地创建的记录发送到CloudKit。当应用程序启动和从后台返回时,我调用此方法。我还为测试阶段编程了一个按钮,它调用这个方法

这种行为似乎完全是随机的。例如,如果我创建了10条记录,其中一些记录被正确上传到CloudKit,而另一些记录则失败。如果我手动重新运行该方法,最终它们都会上传到CloudKit。我一直无法确定成功或失败的模式。在这一点上,我从一个方法中种子测试记录,该方法使记录除了recordName(UUID)和文本字段的后缀之外都是相同的

在有限的测试中,如果我只创建一个记录,它总是有效的

如果我只创造了两个记录,那就是偶尔的失败

如果我创造了五个记录,几乎总是有一个失败

在modifyRecordsCompletionBlock中,无论上载是否成功,updateSavedToCloudKitSuccess()和CleanupMPFile()始终正确完成

我还试着增加超时时间,这完全没有什么区别

任何指导都将不胜感激。Xcode 8.3.3 iOS10 Swift 3

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条记录运行了一个测试——没有错误。谢谢