我有一個應用程序使用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
然後我通過獲取職位user
CKReference
迭代,以獲得創建該帖子的相應用戶,然後構建我的帖子以向用戶呈現UICollectionView
。
用這種方法我遇到了一個問題。
我做了10個職位,其中post1
被user1
創建,由user2
創建post2
,post3
由user1
創建,post4
由user2
創建(等等...)
10個職位測試由這兩個用戶創建,一次一個。
當我遍歷FOR LOOP
來獲取用戶時,以某種方式獲得的訂單不是正確的,它混合了用戶訂單。
我希望看到user1
,user2
,user1
,user2
等..
但我給user1
,user1
,user2
,user1
全部混合,並在奇數階,如果我刷新給出訂貨會與前一個不同。
即使我在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
抓取索引是正確的之前,但由於環比去的方式更快抓取,抓取內部的索引失序,所以這使我損壞了我的數組。
克服這個問題的最好方法是什麼?我應該在物品完成時對它們進行分類嗎?如果是的話,最好的辦法是什麼?
正是我想對數組進行排序。我可能會修改'userRecords'類型爲'[Int:User]'和'int'屬性,我會追加當前的'index',然後當它完成時,我將根據索引(0 ... 9)並返回一個數組排序:D –
@IvanCantarino好,如果這個答案幫助你,請接受它 – 3stud1ant3