嵌套的Cloudkit查询不能以正确的顺序打印

问题描述

我的代码打印顺序不正确。我认为这与我使用main分配方式有关。我想传递一个老板ID。找到具有该ID的用户,然后获取其SubscribedBosses数组。对于该数组中的每个ID,查询用户并返回该用户的screenName。将这些screenName附加到userArray。之后,完成GetBossSubs函数并返回userArray(screenNames数组)。

现在{。{1}}的结果正在运行,而.onAppear中的功能实际上尚未完成。 .onAppearUser 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))