Swift:For循环等待直到响应并根据响应返回值

Gal*_*har 1 database networking swift

我是新手,我正在练习网络。

我有一个孩子身份证的清单。完整的孩子信息存储在Firebase数据库中。数据库中的每个孩子都有ID和属性isGamer: Bool。我想创建一个函数,该函数将返回第一个孩子,isGamer==true. 而我在想的逻辑是:一个for循环,该循环将在列表上运行,如果isGamer == true有的话,将检查第一个孩子,返回孩子的ID,否则继续搜索。我认为这是可行的,尽管我不知道如何处理所有这些异步内容,如何使for循环等待响应等。

主要功能将管理一切:

// Mother Function
func printFirstGamer(kidsIds: [String]) {
     print(returnFirstKidIsGamer(kidsIds: kidsIds ))
}
Run Code Online (Sandbox Code Playgroud)

另一个函数将在isGamer == true处找到第一个孩子:

// This is where I'm stuck basically

func returnFirstKidIsGamer(kidsIds: [String]) -> String {
    for kidID in kids {
        // Wait for previous request to finish before trying again.
        DataService.instance.isKidAGamer(kidID: kidID) { (isGamer) in

        }
        // The for loop will wait for response and then if isGamer==false, will continue, if isGamer==true will return 
    }
    // return first kid where isGamer == true

}
Run Code Online (Sandbox Code Playgroud)

我将使用此功能检查每个孩子的isGamer:

func isKidAGamer(kidID: String, completed: @escaping isKidAGamerCompleted) {
        mainRef.child("Kids").child(kidID).child("isGamer").observeSingleEvent(of: .value, with: { (result) in
            if result.exists() {
                let isGamer = result.value as! Bool
                completed(isGamer)
            } else {
                completed(false)
            }
        })
    }
Run Code Online (Sandbox Code Playgroud)

注意:我不想使用查询,我正在练习(:

谢谢 (:

Rob*_*ier 5

可以使用DispatchGroup使其同步,但是绝对不能在主队列上调用它。

// Blocking function. Must not be called on main queue!
func returnFirstKidIsGamer(kidsIds: [String]) -> String? {
    let group = DispatchGroup()
    var result: String? = nil

    for kidID in kidsIds {
        // Wait for previous request to finish before trying again.
        group.enter()
        DataService.instance.isKidAGamer(kidID: kidID) { (isGamer) in
            if isGamer {
                result = kidId
            }
            group.leave()
        }
        group.wait()
        guard result == nil else { break }
    }
    return result
}
Run Code Online (Sandbox Code Playgroud)

这会group.enter()在进入每个循环之前以及group.leave()每个步骤完成时调用。然后,它等待该步骤完成,然后继续。

此功能是同步的。它会阻塞队列,因此绝对不能在主队列上调用它。您必须使用以下内容将其移至后台:

DispatchQueue.global(qos: .userInitiated).async {
    let kidId = returnFirstKidIsGamer(kidsIds: [kids])
    DispatchQueue.main.async {
        doSomethingInTheUIWithValue(kidId)
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这返回String?,而不是String,因为找不到ID。

通常,您不应该这样做。您应该使用查询。但这是您在需要时将异步功能转换为同步功能的方式。