Swift 立即访问Firebase块中的值/避免竞争条件
我有一个bool“alreadyHaveProfile”,在while循环中我将其更改为TRUE,然后我打破了循环…但是布尔值仍然没有改变。有什么想法吗Swift 立即访问Firebase块中的值/避免竞争条件,swift,firebase,firebase-realtime-database,boolean,Swift,Firebase,Firebase Realtime Database,Boolean,我有一个bool“alreadyHaveProfile”,在while循环中我将其更改为TRUE,然后我打破了循环…但是布尔值仍然没有改变。有什么想法吗 if AccessToken.current != nil { fetchUserData() DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.5) { let dref = FIRDatabase.databa
if AccessToken.current != nil {
fetchUserData()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.5) {
let dref = FIRDatabase.database().reference().child("CheckUsers")
dref.observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in
var alreadyHaveProfile = false
let enumerator = snapshot.children
loop: while let user = enumerator.nextObject() as? FIRDataSnapshot {
if user.key == userID {
alreadyHaveProfile = true
break loop
}
}
}, withCancel: { (error: Error) in
print(error.localizedDescription)
})
print(alreadyHaveProfile)
**最新答复:
if AccessToken.current != nil {
fetchUserData()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.5) {
let dref = FIRDatabase.database().reference().child("CheckUsers")
dref.observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in
var alreadyHaveProfile = false
let enumerator = snapshot.children
loop: while let user = enumerator.nextObject() as? FIRDataSnapshot {
if user.key == userID {
alreadyHaveProfile = true
self.finishSetUp()
break loop
}
}
}, withCancel: { (error: Error) in
print(error.localizedDescription)
})
}
finishSetUp() {
print(alreadyHaveProfile)
if !alreadyHaveProfile {
// finish set up, value of ALREADYHAVEPROFILE is recent and updated.
}
}
异步块内的AcessalreadyHaveProfile变量 下面是代码:
if AccessToken.current != nil {
fetchUserData()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.5) {
let dref = FIRDatabase.database().reference().child("CheckUsers")
dref.observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in
var alreadyHaveProfile = false
let enumerator = snapshot.children
loop: while let user = enumerator.nextObject() as? FIRDataSnapshot {
if user.key == userID {
alreadyHaveProfile = true
print(alreadyHaveProfile)
break loop
}
}
}, withCancel: { (error: Error) in
print(error.localizedDescription)
})
Firebase方法
observeSingleEvent(of:with:)
是异步的。也就是说,该方法在回调运行之前返回
如果像我在这里所做的那样将print语句添加到代码中,我想您会看到代码中第二个出现的print
语句是第一个出现在Xcode控制台中的语句
if AccessToken.current != nil {
fetchUserData()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.5) {
let dref = FIRDatabase.database().reference().child("CheckUsers")
dref.observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in
var alreadyHaveProfile = false
let enumerator = snapshot.children
loop: while let user = enumerator.nextObject() as? FIRDataSnapshot {
if user.key == userID {
alreadyHaveProfile = true
print("1: \(alreadyHaveProfile)")
break loop
}
}
}, withCancel: { (error: Error) in
print(error.localizedDescription)
})
print("2: \(alreadyHaveProfile)")
我怀疑变量
alreadyHaveProfile
的状态尚未由循环中运行的逻辑设置。但是,如果没有完整的场景设置,就很难进行诊断
有两件事要考虑;首先,看起来FireBase正在执行一些数据库查询来设置变量的状态。要调试此过程,请尝试并设置一种方法来观察while循环的每次迭代运行,这样您就可以知道在将print语句输出到控制台之前是否设置了变量alreadyHaveProfile
的状态
这可能有助于确定您是否处于比赛状态
let dref = FIRDatabase.database().reference().child("CheckUsers")
dref.observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in
var alreadyHaveProfile = false
var index = 0
if let userObjects = snapshot.children.allObjects {
for user in userObjects {
if user.key == userID {
alreadHaveProfile = true
}
index += 1
print("Value: \(alreadHaveProfile) at index: \(index) in count: \(userObjects.count)")
if index == userObjects.count {
print("Loop has completed: with value of: \(alreadHaveProfile)")
}
}
}
}, withCancel: { (error: Error) in
print(error.localizedDescription)
})
print("Setting initial value: \(alreadyHaveProfile)")
第二个要考虑的是,用户可能。密钥和用户ID根本不匹配,并且<代码> ALLRIDYHAVEPrime<代码>值被正确设置。要调试此操作,请在循环中设置一些断点,以便在循环的每个迭代中查看
user.key
和userID
。打印(alreadyHaveProfile)不是在同步块之前执行的吗?您可以简化该循环:alreadyHaveProfile=snapshot.children.contains(其中:{($0 as?FIRDataSnapshot)?.key==userID
@Alexander smooth man,感谢您提供的有用信息!我还有另一个IF块,它在上面的第二个print语句之后检查ALREADYHAVEPROFILE的值……有没有办法访问更新后的值?因为我必须等到observeSingleEvent块运行之后才能接收upalreadyHaveProfile的日期真值。没有回答问题…很抱歉,你明白了,伙计…这是一个竞争条件。在循环外的print语句执行后,我的值变为真。那么,在执行查询后立即访问更新的布尔值的最佳选项是什么?很高兴我能提供帮助!我会说如果observeSingleEvent()方法有一个到闭包的完成块,这将是一个很好的开始。否则,您还可以通过检查循环是否已完成来访问alreadHaveProfile
的值。if index==userObjects.count{print(“具有值的已完成循环:\(alreadHaveProfile)”)
是的,你是对的。我将其从我的答案中删除。更好的选择当然是查看是否有完成块可用。我提供的例程将作为临时解决方案。你也可以查看调度组作为同步执行逻辑的选项。感谢你的帮助!我能够想出一个非常简单的解决方案绝对正确!很高兴我们能够一起为您找到解决方案!