我是斯威夫特的新手,我正在练习网络。
我有一个孩子ID列表。完整的孩子信息存储在Firebase数据库中。数据库中的每个孩子都有一个ID
和一个属性isGamer: Bool
。
我想创建一个函数,它将返回isGamer==true.
的第一个孩子
我正在考虑的逻辑是:
一个for循环,它将在列表上运行并将检查第一个小孩isGamer == true
如果是,返回孩子的ID,否则继续搜索。
我认为它会工作,虽然我不知道如何处理所有这些异步的东西,我怎么能让for循环等待响应等。
主要功能将管理一切:
// Mother Function
func printFirstGamer(kidsIds: [String]) {
print(returnFirstKidIsGamer(kidsIds: kidsIds ))
}
另一个函数会找到第一个孩子,其中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
}
我将使用此功能检查每个孩子的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)
}
})
}
注意:我不想使用查询,我练习(
谢谢(:
答案 0 :(得分:4)
可以使用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
}
在进入每个循环之前调用group.enter()
,在每个步骤完成时调用group.leave()
。然后等待完成该步骤,然后继续。
此功能是同步的。它会阻塞队列,因此绝不能在主队列上调用。你必须用这样的东西把它移到后台:
DispatchQueue.global(qos: .userInitiated).async {
let kidId = returnFirstKidIsGamer(kidsIds: [kids])
DispatchQueue.main.async {
doSomethingInTheUIWithValue(kidId)
}
}
请注意,这会返回String?
,而不是String
,因为找不到ID。
通常,你不应该这样做。您应该使用查询。但这就是在需要时将异步函数转换为同步函数的方法。