嵌套 Cloudkit 查询未按正确顺序打印
Nested Cloudkit queries not printing in the right order
我的代码打印顺序不正确。我认为这是我使用 dispatch to main 的方式的问题。我想传入一个老板ID。找到具有该 ID 的用户,然后获取他们的 SubscribedBosses 数组。对于该数组中的每个 ID,查询该用户和 return 该用户的 screenName。将这些 screenName 附加到 userArray。之后完成 GetBossSubs 函数和 return userArray(屏幕名称数组)。
现在 .onAppear
的结果是 运行 在 .onAppear 中的函数实际完成之前。 User Appended
在 Found TestUserName
之前打印
static func getBossSubs(bossID: String, completion: @escaping (Result<UserNames, Error>) ->
()) {
let pred = NSPredicate(format: "uniqueID = %@", bossID)
let sort = NSSortDescriptor(key: "creationDate", ascending: false)
let query = CKQuery(recordType: RecordType.Users, predicate: pred)
query.sortDescriptors = [sort]
let operation = CKQueryOperation(query: query)
operation.desiredKeys = ["subscribedBosses"]
operation.resultsLimit = 50
operation.recordFetchedBlock = { record in
DispatchQueue.main.async {
guard let subs = record["subscribedBosses"] as? [String] else {
print("Error at screenName")
completion(.failure(CloudKitHelperError.castFailure))
return
}
let userArray = UserNames() //Error that it should be a LET is here.
for boss in subs{
CloudKitHelper.getBossScreenName(bossID: boss) { (result) in
switch result{
case .success(let name):
userArray.names.append(name) //works fine
print("Found \(userArray.names)") //Prints a name
case .failure(let er):
completion(.failure(er))
}
}
}
print("does this run?") // Only runs if No Name
completion(.success(userArray)) // contains no name or doesn't run?
}
}
operation.queryCompletionBlock = { (_, err) in
DispatchQueue.main.async {
if let err = err {
completion(.failure(err))
return
}
}
}
CKContainer.default().publicCloudDatabase.add(operation)
}
我这样调用代码:
.onAppear {
// MARK: - fetch from CloudKit
self.userList.names = []
let myUserID = UserDefaults.standard.string(forKey: self.signInWithAppleManager.userIdentifierKey)!
// get my subs projects
CloudKitHelper.getBossSubs(bossID: myUserID) { (results) in
switch results{
case .success(let user):
print("Users appended")
self.userList.names = user.names
case .failure(let er):
print(er.localizedDescription)
}
}
}
这是因为您 运行 一个异步函数在 另一个 异步函数中。
// this just *starts* a series of asynchronous functions, `result` is not yet available
for boss in subs {
CloudKitHelper.getBossScreenName(bossID: boss) { result in
switch result {
case .success(let name):
userArray.names.append(name) // works fine
print("Found \(userArray.names)") // Prints a name
case .failure(let er):
completion(.failure(er))
}
}
}
// this will run before any `CloudKitHelper.getBossScreenName` finishes
completion(.success(userArray))
一个可能的解决方案可能是检查所有 CloudKitHelper.getBossScreenName
函数是否完成(例如,通过检查 userArray
的大小)然后才 return 完成:
for boss in subs {
CloudKitHelper.getBossScreenName(bossID: boss) { result in
switch result {
case .success(let name):
userArray.names.append(name)
if userArray.names.count == subs.count {
completion(.success(userArray)) // complete only when all functions finish
}
case .failure(let er):
completion(.failure(er))
}
}
}
// do not call completion here, wait for all functions to finish
// completion(.success(userArray))
我的代码打印顺序不正确。我认为这是我使用 dispatch to main 的方式的问题。我想传入一个老板ID。找到具有该 ID 的用户,然后获取他们的 SubscribedBosses 数组。对于该数组中的每个 ID,查询该用户和 return 该用户的 screenName。将这些 screenName 附加到 userArray。之后完成 GetBossSubs 函数和 return userArray(屏幕名称数组)。
现在 .onAppear
的结果是 运行 在 .onAppear 中的函数实际完成之前。 User Appended
在 Found TestUserName
static func getBossSubs(bossID: String, completion: @escaping (Result<UserNames, Error>) ->
()) {
let pred = NSPredicate(format: "uniqueID = %@", bossID)
let sort = NSSortDescriptor(key: "creationDate", ascending: false)
let query = CKQuery(recordType: RecordType.Users, predicate: pred)
query.sortDescriptors = [sort]
let operation = CKQueryOperation(query: query)
operation.desiredKeys = ["subscribedBosses"]
operation.resultsLimit = 50
operation.recordFetchedBlock = { record in
DispatchQueue.main.async {
guard let subs = record["subscribedBosses"] as? [String] else {
print("Error at screenName")
completion(.failure(CloudKitHelperError.castFailure))
return
}
let userArray = UserNames() //Error that it should be a LET is here.
for boss in subs{
CloudKitHelper.getBossScreenName(bossID: boss) { (result) in
switch result{
case .success(let name):
userArray.names.append(name) //works fine
print("Found \(userArray.names)") //Prints a name
case .failure(let er):
completion(.failure(er))
}
}
}
print("does this run?") // Only runs if No Name
completion(.success(userArray)) // contains no name or doesn't run?
}
}
operation.queryCompletionBlock = { (_, err) in
DispatchQueue.main.async {
if let err = err {
completion(.failure(err))
return
}
}
}
CKContainer.default().publicCloudDatabase.add(operation)
}
我这样调用代码:
.onAppear {
// MARK: - fetch from CloudKit
self.userList.names = []
let myUserID = UserDefaults.standard.string(forKey: self.signInWithAppleManager.userIdentifierKey)!
// get my subs projects
CloudKitHelper.getBossSubs(bossID: myUserID) { (results) in
switch results{
case .success(let user):
print("Users appended")
self.userList.names = user.names
case .failure(let er):
print(er.localizedDescription)
}
}
}
这是因为您 运行 一个异步函数在 另一个 异步函数中。
// this just *starts* a series of asynchronous functions, `result` is not yet available
for boss in subs {
CloudKitHelper.getBossScreenName(bossID: boss) { result in
switch result {
case .success(let name):
userArray.names.append(name) // works fine
print("Found \(userArray.names)") // Prints a name
case .failure(let er):
completion(.failure(er))
}
}
}
// this will run before any `CloudKitHelper.getBossScreenName` finishes
completion(.success(userArray))
一个可能的解决方案可能是检查所有 CloudKitHelper.getBossScreenName
函数是否完成(例如,通过检查 userArray
的大小)然后才 return 完成:
for boss in subs {
CloudKitHelper.getBossScreenName(bossID: boss) { result in
switch result {
case .success(let name):
userArray.names.append(name)
if userArray.names.count == subs.count {
completion(.success(userArray)) // complete only when all functions finish
}
case .failure(let er):
completion(.failure(er))
}
}
}
// do not call completion here, wait for all functions to finish
// completion(.success(userArray))