2014-07-01 13 views
7

Ho testato fuori CloudKit come vorrei per rilasciare un app di utilizzarlo quando si verifica il rilascio di iOS 8. Sembra abbastanza semplice per salvare i dati utilizzando il seguente codice:Salvataggio dati modificati in CloudKit

CKRecordID * recordID = [[CKRecordID alloc] initWithRecordName:@"basicRecord"]; 
CKRecord * record = [[CKRecord alloc] initWithRecordType:@"basicRecordType" recordID:recordID]; 
[record setValue:@"defaultValue" forKey:@"defaultKey"]; 
CKDatabase *database = [[CKContainer defaultContainer] publicCloudDatabase]; 
[database saveRecord:record completionHandler:^(CKRecord *record, NSError *error) { 

    if (error) { 
     NSLog(@"Error: %@", error); 
    } else { 
     NSLog(@"Record Saved!"); 
    } 
}]; 

e non ho ricevuto errori da questo. Tuttavia, se si tenta di eseguire nuovamente il codice, forse perché ho cambiato il valore record

[record setValue:@"newValue" forKey:@"defaultKey"]; 

ricevo un errore che pone la domanda, come posso fare per salvare un pezzo modificato di dati. Dopotutto, questa è una parte fondamentale del salvataggio di cose nel cloud. L'errore è qui sotto e tutto l'aiuto sarebbe molto apprezzato, non esitate a chiedere ulteriori informazioni.

Error: <CKError 0x17024afb0: "Server Record Changed" (14/2017); "Error saving record <CKRecordID: 0x144684a80; basicRecord:(_defaultZone:__defaultOwner__)> to server: (null)"; uuid = 182C497F-966C-418A-9E6A-5563BA6CC6CD; container ID = "iCloud.com.yourcompany.CloudKit"> 

risposta

11

Questo errore è probabilmente perché saveRecord: funziona solo per i nuovi record o record che sono più recenti rispetto alla versione sul server:

Questo metodo salva il record solo se non è mai stato salvato prima o se è più recente della versione sul server. Non è possibile utilizzare questo metodo per sovrascrivere le versioni più recenti di un record sul server. CKDatabase docs

L'approccio consigliato per modificare un record esistente (o set di record) è quello di utilizzare un insieme CKModifyRecordsOperation con il savePolicy desiderata per affrontare i conflitti:

Dopo aver modificato i campi di un record, utilizzare questo tipo di oggetto operazione per salvare tali modifiche in un database. (...) Quando si salvano i record, il valore nella proprietà savePolicy determina come procedere quando vengono rilevati conflitti sul server. CKModifyRecordsOperation docs

1

Dalla documentazione di CKRecord:

nuovi record esistono solo nella memoria fino a quando non li salva in modo esplicito a iCloud.

Quando si imposta il nuovo valore [record setValue:@"newValue" forKey:@"defaultKey"]; è già stato salvato il record, rendendolo invalido.

È possibile utilizzare CKModifyRecordsOperation e nella maggior parte delle situazioni potrebbe essere preferibile, ma non necessario. Basta recuperare i dati utilizzando una nuova CKRecord, quindi alimentare il record in saveRecord: come descritto here.

0

Dopo aver salvato il record, prendere in modo che il record retured avrà quindi la RecordID che Cloudkit aggiunto

Allora, in quel stesso record inverosimile, utilizzare setValue per modificare i dati che si desidera modificare

quindi è possibile utilizzare CFModifyRecordsOperation nell'esempio sottostante, cachedCKRecordsServiceCenter contiene i record recuperati da cloudkit e quei dischi hanno il cloudKit RecordID del in loro ......

  //find this service center in the cached records 
      for (_,serviceCenter) in (theModel?.cachedCKRecordsServiceCenter.enumerated())! //is data for logged in Co ONLY with NO Co name attached 
      { 
       let name = serviceCenter["name"] as! String 
       returnValue = "Try Again" 
       if name == displayedRecordName 
       { 
        serviceCenter.setValue(displayedRecordName! + "_" + (theModel?.companyName)!, forKey: "name") //db values have Co name appended 
        serviceCenter.setValue(label2Text.text, forKey:"street1") 
        serviceCenter.setValue(label3Text.text, forKey:"street2") 
        serviceCenter.setValue(label4Text.text, forKey:"city") 
        serviceCenter.setValue(label5Text.text, forKey:"state") 
        serviceCenter.setValue(label6Text.text, forKey:"zip") 
        serviceCenter.setValue(label7Text.text, forKey:"phone") 
        serviceCenter.setValue(label8Text.text, forKey:"email") 
        serviceCenter.setValue(label9Text.text, forKey:"note") 

        let saveRecordsOperation = CKModifyRecordsOperation() 

        var ckRecordsArray = [CKRecord]() 
        // set values to ckRecordsArray 
        ckRecordsArray.append(serviceCenter) 

        saveRecordsOperation.recordsToSave = ckRecordsArray 
        saveRecordsOperation.savePolicy = .ifServerRecordUnchanged 

        appDelegate.locked = true 
        saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in 
         if error != nil { 
          // Really important to handle this here 
          ////////print("ERROR: Unable to update Driver Location: Error= \(error)") 
          self.returnValue = "ERROR: Unable to update Driver Location: ERROR = \(error)" 
          self.appDelegate.locked=false 
         } 
         else 
         { 
          ////print("Successfully updated Service Center") 
          self.appDelegate.locked=false 
          self.returnValue = "Successfully updated Service Center" 
          self.appDelegate.locked=false 

          //reget the data into the cach 
          self.theModel?.fetchServiceCenterFromCloudKit1() 
         } 

        } 

        CKContainer.default().publicCloudDatabase.add(saveRecordsOperation) 
       } 
      }