我有一个使用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
创建,post2
由user2
创建,post3
由{创建{1}},user1
由post4
创建(依此类推......)
这两个用户创建的10个帖子,一次一个。
当我在user2
中迭代以获取用户时,不知何故获得的订单不是正确的,它会混合用户订单。
我希望看到FOR LOOP
,user1
,user2
,user1
等...
但是我给了user2
,user1
,user1
,user2
所有混合和奇数顺序,如果我刷新给定的顺序将不同于前一个。
即使我在user1
操作中出现record.recordID
时出错,它也应该与fetch
不同。
我可能会发生这种情况,因为查询是异步进行的,输入可能是错误的(在查询完成之前再进行一次迭代)并且要获取的reference.recordID
是错误的,但是为了发生这种情况我不会我认为没有提取10个帖子,但我得到了它们 - 帖子被正确提取但用户却没有。
为了进行测试,我创建了一个递归函数,该函数仅在成功获取上一个用户时从服务器获取下一个用户,并且我注意到现在用户已正确获取。
这是我的递归函数:
recordID
我在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)
}
}
内部调用它取代之前的for循环,如下所示:
queryCompletionBlock
通过这种方式,我保证相应帖子的用户不会出错,但有了这个,我就有了巨大的性能块。
使用常规for循环,我的函数执行时间如下:
执行时间:1.15568399429321
使用递归函数,它是这样的:
执行时间:4.56143599748611
正如您所注意到的那样,它几乎是其中的4倍。
这是我的问题:
在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)
中的错误吗?
谢谢。 问候。
修改
经过一些测试后,我已完成以下CloudKit
:
For loop
正如你所看到的,我试图在fetch之前和之内跟踪索引,这些是打印:
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)")
}
})
}
在获取索引之前,索引是正确的,但由于循环比fetch更快,因此fetch中的索引会出现故障,因此我破坏了我的数组。
克服这个问题的最佳方法是什么?我应该在完成后对对象进行排序吗?如果是这样,最好的方法是什么?
答案 0 :(得分:0)
由于您正在使用异步调用的用户,这就是用户的顺序不同的原因,第一次用户引用的请求有时可能比user2花费更多的时间,因此user2被添加到user1之前的数组中,
现在你可以做些什么:
您可以选择在调用后对结果进行排序
对数组进行排序,您可以使用sortdescriptor