此应用程序使用CloudKit在本地设备上存储记录和核心数据。本地创建的记录保存到核心数据。调用以下方法将在本地创建的记录发送到CloudKit。我在应用程序启动和从后台返回时调用此方法。我还为调用此方法的测试阶段编程了一个按钮。
这种行为似乎完全是随机的。例如,如果我创建10条记录,其中一些记录会正确上载到CloudKit,而另一些记录则会失败。如果我手动重新运行该方法,最终它们都会上传到CloudKit。我一直无法确定成功或失败的模式。在这一点上,我从一个方法种子测试记录,该方法使记录完全相同,除了recordName(UUID)和文本字段的后缀。
有限的测试,如果我只创建一个记录,它总是有效的。
如果我只创造了两张唱片,那就是偶尔的失败。
如果我创造了五张唱片,几乎总是失败的。
在modifyRecordsCompletionBlock中,无论上载是否成功,updateSaveToCloudKitSuccess()和cleanUpTmpFile()始终正确完成。
我也试着增加超时时间,这完全没有区别。
任何指导都将不胜感激。Xcode 8.3.3 iOS10斯威夫特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

控制台输出示例:
NOresults.count为:7
修改记录操作成功
savedToCloudKit=真
modifyRecordsOperation中的错误未能修改某些记录
savedToCloudKit=假
modifyRecordsOperation中的错误未能修改某些记录
savedToCloudKit=假
modifyRecordsOperation中的错误未能修改某些记录
savedToCloudKit=假
modifyRecordsOperation中的错误未能修改某些记录
savedToCloudKit=假
修改记录操作成功
savedToCloudKit=真
修改记录操作成功
savedToCloudKit=真
根据rmaddy和paulw11的评论,我实现了perRecordCompletionBlock,发现错误总是与CKAsset文件有关。我将查看是否在完成块执行之前清除了该临时文件。
perRecordCompletionBlock:“;
dateCreated=“2017-08-21 22:20:25+0000”;
出生日期=“2017-04-23 22:20:25+0000”;
firstname=FirstName12;
姓氏=ZLastName12;
myRecordName=“7621A7BD-7D32-4984-8117-2189D6F40D5F”;
notes=“这是便笺号码12”;
patientlistparent=“;
PrimaryMedical=“Who12医生”;
ssan=123456789;
},记录类型=患者>。错误:可选()
modifyRecordsOperation中的错误未能修改某些记录
savedToCloudKit=假

最佳答案

我通过将资产保存操作放在同步全局队列中解决了这个问题。

    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

10-08 12:13