2017-08-05 14 views
0

我正在創建一個將記錄保存到CloudKit的應用程序,並將數據本地存儲在Core Data中。我確實可以在兩個位置保存記錄,但是當與iCloud的連接不可用或存在保存錯誤時,我需要能夠處理錯誤。我想我可以在CKModifyRecordsOperation完成塊中填充一個變量來區分,但這不起作用 - 即使過程成功,來自CloudKit保存的返回值始終爲false。這個想法是首先保存到CloudKit,然後檢索recordID並將其保存爲Core Data保存。從CloudKit返回Bool保存CompletionHandler不正確

這是我的代碼,我從barbutton中調用doTheComboSave()。控制檯輸出在代碼下面。任何意見,將不勝感激。 xcode的8.3.3,夫特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 

控制檯輸出:

blockSavedToCloudKit是假

標誌爲假

saveTwoFiles是假

completionHandler(國旗)是假的

完成塊已經運行,但保存到CloudKit的文件失敗。在modifyRecordsOperation

成功

currentRecordName是:B53DCFB8-0EFB-4E79-8762-FECCEFBA9BD8

+0

我想你並不瞭解CloudKit /網絡調用的異步特性。在操作完成之前返回從saveNewCloudKitRecord返回的假。你需要一個障礙或信號量來使它在你的例子中以你期望的方式返回。 – agibson007

回答

0

見上面從Ichydon評論。

saveNewCloudKitRecord()函數在completionHandler設置我想要使用的布爾值之前返回。整個想法是首先創建CloudKit記錄,以便我可以檢索recordName以存儲在Core Data中,以同步本地和雲記錄。

更好的方法是首先保存到核心數據,但自己創建CKRecordID,並在保存到CloudKit時將其記錄到記錄中。

在函數保存核心數據記錄:

let myRecordName = UUID().uuidString 

然後返回一個字符串作爲CloudKit保存的參數使用。

let myRecordID : CKRecordID = CKRecordID(recordName: myRecordName, zoneID: (recordZone?.zoneID)!) 

let myRecord = CKRecord(recordType: "Whatever", recordID : myRecordID) 

希望這可以幫助別人。