Je crée une application qui enregistre des enregistrements dans CloudKit et stocke également les données localement dans les données de base. Je peux en effet enregistrer des enregistrements dans les deux emplacements, mais je dois être capable de gérer les erreurs lorsqu'une connexion à iCloud n'est pas disponible ou qu'il y a une erreur de sauvegarde. J'ai pensé que je pourrais remplir une variable dans le bloc d'achèvement CKModifyRecordsOperation
pour différencier, mais cela ne fonctionne pas - la valeur de retour de la sauvegarde CloudKit est toujours fausse, même si le processus réussit. L'idée est d'enregistrer d'abord dans CloudKit, puis de récupérer l'ID d'enregistrement et de l'enregistrer avec l'enregistrement des données de base.Renvoyer Bool à partir de CloudKit Enregistrer CompletionHandler Not Correct
Voici mon code, j'appelle doTheComboSave()
à partir d'un barbutton. La sortie de la console est en dessous du code. Tout avis sera le bienvenu. Xcode 8.3.3, Swift 3, iOS 10.
func saveNewCloudKitRecord() -> Bool {
privateDatabase = container().privateCloudDatabase
recordZone = CKRecordZone(zoneName: "myPatientZone")
var blockSavedToCloudKit = false
let myRecord = CKRecord(recordType: "Patient", zoneID: (recordZone?.zoneID)!)
myRecord.setObject(firstNameTextField.text as CKRecordValue?, forKey: "firstname")
myRecord.setObject(lastNameTextField.text as CKRecordValue?, forKey: "lastname")
let parentRefID = CKRecordID(recordName: "047EBE6C-AB1C-0183-8D80-33C0E4AE228B", zoneID: (recordZone?.zoneID)!)
//
//bunch more record fields
//
let modifyRecordsOperation = CKModifyRecordsOperation(recordsToSave: [myRecord], recordIDsToDelete: nil)
modifyRecordsOperation.timeoutIntervalForRequest = 10
modifyRecordsOperation.timeoutIntervalForResource = 10
modifyRecordsOperation.modifyRecordsCompletionBlock = {
records, recordIDs, error in
if let err = error {
blockSavedToCloudKit = false
//create placeholder record name for later updating
} else {
blockSavedToCloudKit = true
self.currentRecord = myRecord
self.passedInCKRecord = myRecord
}//if err
}//modifyRecordsOperation
privateDatabase?.add(modifyRecordsOperation)
print("blockSavedToCloudKit is \(blockSavedToCloudKit)")
return blockSavedToCloudKit
}//saveNewCloudKitRecord
typealias SavedCompletion = (_ success:Bool) -> Void
func saveTwoFiles(completionHandler : SavedCompletion) {
let flag = saveNewCloudKitRecord()
print("flag is \(flag)")
completionHandler(flag)
print("completionHandler(flag) is \(flag)")
}//makeTheComboSave
func doTheComboSave() {
saveTwoFiles() { (success) -> Void in
print("saveTwoFiles is \(success)")
if success {
//will pass the CKRecord so core data can store the recordID and recordName
saveTheNewRecord()//this is the Core Data save
DispatchQueue.main.async {
self.performSegue(withIdentifier: "unwindToMasterViewController", sender: self)
print("Completion block has been run successfully.")
}//Dispatch
} else {
//create placeholder recordName for later updating
saveTheNewRecord()//this is the Core Data save
DispatchQueue.main.async {
self.performSegue(withIdentifier: "unwindToMasterViewController", sender: self)
print("Completion block has been run but the file save to CloudKit failed.")
}//Dispatch
}//if else
}//block
}//doTheComboSave
Sortie de la console:
blockSavedToCloudKit est fausse
drapeau est faux
saveTwoFiles est fausse
completionHandler (drapeau) est faux
Le bloc d'achèvement a été exécuté mais le fichier enregistré dans CloudKit a échoué.
succès dans modifyRecordsOperation
currentRecordName est: B53DCFB8-0EFB-4E79-8762-FECCEFBA9BD8
Je pense que vous ne comprenez pas la nature asynchrone d'un appel CloudKit/réseau. Le faux retourné par saveNewCloudKitRecord est renvoyé avant que l'opération ne soit terminée. Vous auriez besoin d'une barrière ou d'un sémaphore pour le faire revenir comme vous l'attendez dans votre exemple. – agibson007