2015-06-08 150 views
3

我正在通過將數據從外部Web服務提取到私有CloudKit數據庫的應用程序工作。該應用程序是一個單用戶應用程序,但我遇到了一個競爭條件,我不知道如何避免。CloudKit:防止重複記錄

我的外部數據中的每條記錄都有一個唯一的標識符映射到我的CKRecord實例。一般應用程序的啓動流程如下:

  1. 獲取相關記錄類型的當前CKRecords。
  2. 獲取外部記錄。
  3. 對於每個外部記錄,如果在CloudKit中不存在,則通過批量創建(修改操作)創建它。

現在,問題是,如果此過程在用戶的兩個設備上同時啓動,因爲CK和外部提取都是異步的,所以很有可能會得到重複記錄。

我知道我可以使用區域自動提交所有的CKRecord實例,但我不認爲這解決了我的問題,因爲如果所有這些提取都發生在同一時間,則保存並不是真正的問題。

我的問題是:

  1. 有誰知道的方式在所有用戶的設備的「鎖定」爲寫入專用數據庫?
  2. 另外,有沒有辦法強制CKRecord字段的唯一性?
  3. 或者,有沒有辦法使用自定義值作爲主鍵,在這種情況下,我可以使用我的外部ID作爲CK ID並允許系統防止重複本身。

感謝您的幫助!

+1

所以它看起來像我其實可以傳遞一個自定義名稱到我自己的自定義CKRecordID,任何人都可以告訴我,如果這是正確的方式去做這件事? – nickbona

+1

是的,你可以添加自己的CKRecordID。然後它必須在整個容器中唯一(也可以在多個記錄類型中) –

回答

4

答案:

  1. 不,你不能鎖定專用數據庫
  2. Cloudkit已經強制執行,並假設唯一的記錄ID的
  3. 您可以記錄ID任何你喜歡(在非區一部分)。

說明:

關於你的重複問題。如果您是創建記錄ID的人(例如,您提到的外部記錄),那麼最糟糕的情況是,如果您有競爭條件,則應該有一條記錄,並使用相同的數據寫另一條記錄。我不認爲這是極端情況下的問題,兩個設備同時啓動這個過程。基本上你首先獲取現有記錄然後修改它們的邏輯似乎對我來說聽起來很合理。

代碼:

//employeeID is a unique ID to identify an employee 
let employeeID = "001" 

//Remember the recordID needs to be unique within the same database. 
//Assuming you have different record types, it is better to prefix the record name with the record type so that it is unique 
let recordName = "Employee-\(employeeID)" 

//If you are using a custom zone 
let customZoneID = CKRecordZoneID(zoneName: "SomeCustomZone", ownerName: CKCurrentUserDefaultName) 
let recordIDInCustomZone = CKRecordID(recordName: recordName, zoneID: customZoneID) 

//If you are using the default zone 
let recordIDInDefaultZone = CKRecordID(recordName: recordName) 
0

我有,當我試圖在100多個記錄的數據庫中讀取下載重複的類似問題;該解決方案可以在Apple的Atlas示例中找到,該示例使用布爾值檢查最後一個進程在啓動下一個進程之前是否完成。你發現一塊很像這樣的...

@synchronized (self) 
    { 
     // Quickly returns if another loadNextBatch is running or we have the oldest post 
     if(self.isLoadingBatch || self.haveOldestPost) return; 
     else self.isLoadingBatch = YES; 
    } 

順便提一句,這裏創建您自己的記錄密鑰的代碼。

CKRecordID *customID = [[CKRecordID alloc] initWithRecordName: [globalEOConfirmed returnEOKey:i]]; 
    newrecord = [[CKRecord alloc] initWithRecordType:@"Blah" recordID:customID]; 
+0

當代碼在同一用戶的兩個不同設備上同時運行時,這是不可能的。正確的解決方案是使用自定義的'CKRecordID'。根據唯一字段 – user1046037

+0

構建「CKRecordID」感謝您的反饋。你能用一個合適的解決方案的例子來分享一些代碼嗎? – user3069232

+0

那麼使用一種創建'CKRecordID'的一致方式(就像你在答案中所顯示的那樣),所以當2個設備運行相同的代碼來更新雲記錄時,它們將更新相同的記錄而不是創建單獨的記錄。 '@ synchronized'不提供額外的安全性,因爲它們可能是2個完全不同的設備,唯一的'CKRecordID'就足夠了。 – user1046037