2017-08-17 25 views
0

我有一個應用程序使用CloudKit作爲後端。從循環中的查詢中獲取來自CloudKit的數據檢索錯誤的數據

我有一個Post記錄類型,它有一個user作爲CKReference以跟蹤誰是帖子創建者。

我的post struct構造函數需要一個user作爲輸入,所以我可以「掛載」後顯示。

當我查詢服務器檢索10篇帖子我用下面的代碼:

var postRecords = [CKRecord]() 
var userRecords = [User]() 
let qop = CKQueryOperation(query: q) 
qop.resultsLimit = 10 

qop.recordFetchedBlock = {(record: CKRecord) in 
    postRecords.append(record) 
    let userReference = record["user"] as! CKReference 
    self.userCKReferences.append(userReference) 
} 

qop.queryCompletionBlock = {(cursor, err) in 
    if err != nil { 
     print("queryCompletionBlock error:", err ?? "") 
     return 
    } 

    let start = Date() 

    for reference in self.userCKReferences { 

     database.fetch(withRecordID: reference.recordID, completionHandler: { (tmpUserCKR, err) in 

      if err != nil { 
       print("Error:", err ?? "") 
       return 
      } 


      let tmpUser = User() // custom initializations here 
      userRecords.append(tmpUser) 

      if userRecords.count == postRecords.count { 
       self.assemblePosts(posts: postRecords, users: userRecords, previousCounter: previousPostCounter, firsTime: firstTime) 
       let finish = Date() 
       let executionTime = finish.timeIntervalSince(start) 
       print("Execution time: \(executionTime)") 

      } 
      }) 
    } 
} 
database.add(qop) 

正如你所看到的,我取post然後我通過獲取職位userCKReference迭代,以獲得創建該帖子的相應用戶,然後構建我的帖子以向用戶呈現UICollectionView

用這種方法我遇到了一個問題。

我做了10個職位,其中post1user1創建,由user2創建post2post3user1創建,post4user2創建(等等...)

10個職位測試由這兩個用戶創建,一次一個。

當我遍歷FOR LOOP來獲取用戶時,以某種方式獲得的訂單不是正確的,它混合了用戶訂單。

我希望看到user1user2user1user2等..

但我給user1user1user2user1全部混合,並在奇數階,如果我刷新給出訂貨會與前一個不同。

即使我在fetch操作中打印record.recordID時出錯,它應該是不一樣reference.recordID

雖然這可能會發生,因爲查詢是異步進行的,輸入可能是錯誤的(在查詢結束之前還有一次迭代),並且recordID可能是錯誤的,但是對於這種情況我不會有我認爲這10個帖子被提取了,但我得到了他們 - 帖子被正確提取,但用戶沒有。

爲了進行測試,我創建了一個遞歸函數,只有獲取來自服務器的下一個用戶時,前一個被成功取出,並通過我注意到,現在用戶正確獲取。

這裏是我的遞歸函數:

var refPosition: Int = 0 
var userRecords = [User]() 

func recursiveFetch(list: [CKReference], completion: ((Bool) -> Swift.Void)? = nil) { 
    if refPosition == list.count { 
     // All data fetched 
     completion?(true) 
     refPosition = 0 
     userRecords = [User]() 
     return 
    } 

    let database = CKContainer.default().publicCloudDatabase 
    let id = list[refPosition].recordID 

    database.fetch(withRecordID: id) { (record, err) in 

     if err != nil { 
      print("Failed to fetch user with error:", err ?? "") 
      return 
     } 


     let tmpUser = User() // with some initializations 

     self.userRecords.append(tmpUser) 

     self.refPosition += 1 
     self.recursiveFetch(list: list, completion: completion) 
    } 
} 

,我把它叫做queryCompletionBlock內取代以前的for循環,這是這樣的:

var postRecords = [CKRecord]() 


let qop = CKQueryOperation(query: q) 
qop.resultsLimit = 10 

qop.recordFetchedBlock = {(record: CKRecord) in 
    postRecords.append(record) 
    let userReference = record["user"] as! CKReference 
    self.userCKReferences.append(userReference) 
} 

qop.queryCompletionBlock = {(cursor, err) in 
    if err != nil { 
     print("queryCompletionBlock error:", err ?? "") 
     return 
    } 

    let start = Date() 

    self.recursiveFetch(list: self.userCKReferences, completion: { (success) in 
     if self.userRecords.count == postRecords.count { 
      self.assemblePosts(posts: postRecords, users: self.userRecords) 
      let finish = Date() 
      let executionTime = finish.timeIntervalSince(start) 
      print("Execution time: \(executionTime)") 

     } 
    }) 
} 
database.add(qop) 

這樣,我保證用戶的各自的帖子不會是錯的,但是,我得到了一個巨大的性能塊。

與普通for循環我的函數的執行時間是這樣的:

執行時間:1.15568399429321

並與遞歸函數它是這樣的:

執行時間:4.56143599748611

正如你注意到它幾乎是4倍。

我的問題是:

什麼可能導致數據損壞裏面的for循環?以及如何提高遞歸函數的性能?

難道這是一個錯誤CloudKit

謝謝。 此致敬禮。

編輯

一些測試後,我已經做了以下的For loop

for (i,reference) in self.userCKReferences.enumerated() { 
    print("\nindex:", i) 
    print("recordID:", reference.recordID) 

    database.fetch(withRecordID: reference.recordID, completionHandler: { (tmpUserCKR, err) in 

     print("\nindex inside fetch:", i) 
     print("recordID inside fetch:", reference.recordID) 
     print("fetched recordID:", tmpUserCKR?.recordID) 

     if err != nil { 
      print("Error in reference loop:", err ?? "") 
      return 
     } 


     let tmpUser = User(/* with custom inits*/) 
     userRecords.append(tmpUser) 

     if userRecords.count == postRecords.count { 
      self.assemblePosts(posts: postRecords, users: userRecords, previousCounter: previousPostCounter, firsTime: firstTime) 
      let finish = Date() 
      let executionTime = finish.timeIntervalSince(start) 
      print("Execution time: \(executionTime)") 

     } 
    }) 
} 

正如你所看到的,我之前試過和內取來跟蹤指數,和這些都是打印:

index: 1 
recordID: <CKRecordID: 0x6180002382a0; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 

index: 2 
recordID: <CKRecordID: 0x6180002383c0; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 

index: 3 
recordID: <CKRecordID: 0x618000238200; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 

index: 4 
recordID: <CKRecordID: 0x60000003b600; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 

index: 5 
recordID: <CKRecordID: 0x600000038420; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 

index: 6 
recordID: <CKRecordID: 0x600000036640; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 

index: 7 
recordID: <CKRecordID: 0x600000039b60; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 

index: 8 
recordID: <CKRecordID: 0x60000003b780; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 

index: 9 
recordID: <CKRecordID: 0x60000003b580; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 

index inside fetch: 1 
recordID inside fetch: <CKRecordID: 0x6180002382a0; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x6100000369e0; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 4 
recordID inside fetch: <CKRecordID: 0x60000003b600; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x60000003c640; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 3 
recordID inside fetch: <CKRecordID: 0x618000238200; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x610000035fa0; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 2 
recordID inside fetch: <CKRecordID: 0x6180002383c0; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x610000038f80; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 6 
recordID inside fetch: <CKRecordID: 0x600000036640; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x60000003c640; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 0 
recordID inside fetch: <CKRecordID: 0x608000037b20; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x618000238560; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 7 
recordID inside fetch: <CKRecordID: 0x600000039b60; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x60800003abe0; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 9 
recordID inside fetch: <CKRecordID: 0x60000003b580; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x60000003c780; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 8 
recordID inside fetch: <CKRecordID: 0x60000003b780; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x60000003c7e0; recordName=25221185-4E74-4268-B3E9-3EF3AA435A76, zoneID=_defaultZone:__defaultOwner__>) 

index inside fetch: 5 
recordID inside fetch: <CKRecordID: 0x600000038420; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__> 
fetched recordID: Optional(<CKRecordID: 0x610000039680; recordName=5FF7D994-7F0D-4F1F-90A2-BB765EB52E27, zoneID=_defaultZone:__defaultOwner__>) 
Execution time: 1.74884396791458 

抓取索引是正確的之前,但由於環比去的方式更快抓取,抓取內部的索引失序,所以這使我損壞了我的數組。

克服這個問題的最好方法是什麼?我應該在物品完成時對它們進行分類嗎?如果是的話,最好的辦法是什麼?

回答

0

由於您正在獲取用戶使用異步調用,這就是爲什麼用戶的順序不同,所以對第一個用戶引用的請求可能需要比user2更多的時間,因此在user1之前將user2添加到數組中,

現在你可以做的:

一個選擇是那種通話

後的結果,你可以使用sortdescriptor

+0

正是我想對數組進行排序。我可能會修改'userRecords'類型爲'[Int:User]'和'int'屬性,我會追加當前的'index',然後當它完成時,我將根據索引(0 ... 9)並返回一個數組排序:D –

+0

@IvanCantarino好,如果這個答案幫助你,請接受它 – 3stud1ant3

相關問題