2014-07-01 8 views
7

Testowałem CloudKit, ponieważ chcę opublikować aplikację z nią korzystającą, gdy pojawi się wydanie iOS8. Wydaje się dość proste, aby zapisać dane za pomocą poniższego kodu:Zapisywanie zmodyfikowanych danych w 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!"); 
    } 
}]; 

i nie otrzymuję z tego żadnych błędów. Jednakże, jeśli próbuję ponownie uruchomić kod, może dlatego, że zmieniły się wartości zapisu do

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

Otrzymuję błąd, który nasuwa się pytanie, jak mogę iść o zapisaniu zmodyfikowanego fragmentu danych. W końcu jest to podstawowa część ratowania rzeczy w chmurze. Błąd jest poniżej i każda pomoc będzie bardzo mile widziana, nie wahaj się poprosić o dalsze informacje.

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"> 

Odpowiedz

11

Błąd ten jest prawdopodobnie dlatego saveRecord: działa tylko dla nowych zapisów lub zapisów, które są nowsze niż wersja na serwerze:

Metoda ta zapisuje rekord tylko wtedy, gdy nie została zapisana przed lub jeśli jest nowsza niż wersja na serwerze. Nie można użyć tej metody do zastąpienia nowszych wersji rekordu na serwerze. CKDatabase docs

Zalecane podejście do modyfikacji istniejącego rekordu (lub zestaw rekordów) jest użycie CKModifyRecordsOperation zestaw z pożądanym savePolicy do czynienia z konfliktami:

Po zmodyfikowaniu pola rekordu, użyj tego typu obiektu operacji, aby zapisać zmiany w bazie danych. (...) Podczas zapisywania rekordów wartość właściwości savePolicy określa sposób postępowania w przypadku wykrycia konfliktów na serwerze. CKModifyRecordsOperation docs

1

Od docs CKRecord:

Nowe rekordy istnieją tylko w pamięci, dopóki jawnie zapisać je do iCloud.

Po ustawieniu nowej wartości [record setValue:@"newValue" forKey:@"defaultKey"]; już zapisano rekord, co czyni go nieważnym.

Możesz użyć CKModifyRecordsOperation iw większości sytuacji może być to preferowane, ale nie musisz tego robić. Po prostu pobierz swoje dane, używając świeżego CKRecord, a następnie przekaż ten rekord do saveRecord:, zgodnie z opisem here.

0

Po zapisaniu rekordu, sprowadzić go tak, że retured zapis będzie wówczas mieć recordID że Cloudkit dodany

Następnie na tej samej pobranego rekordu, użyj setValue zmienić dane, które chcesz zmienić

następnie można użyć CFModifyRecordsOperation w poniższym przykładzie cachedCKRecordsServiceCenter zawiera pobranych rekordów z cloudkit i te zapisy mają CloudKit recordID jest w nich ......

  //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) 
       } 
      }