问题描述
我的代码打印顺序不正确。我认为这与我使用main分配方式有关。我想传递一个老板ID。找到具有该ID的用户,然后获取其SubscribedBosses数组。对于该数组中的每个ID,查询该用户并返回该用户的screenName。将这些screenName附加到userArray。之后,完成GetBossSubs函数并返回userArray(screenNames数组)。
现在{。{1}}的结果正在运行,而.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)
}
解决方法
这是因为您在另一个异步函数中运行了一个异步函数。
// 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
的大小),然后仅返回完成:
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))