我的代码有问题:
func calculaGastos() -> Float{
let idUser = Auth.auth().currentUser?.displayName
var total : Float = 0
let ref = Database.database().reference().child("Users").child(idUser!).child("Gastos")
ref.observeSingleEvent(of: .value) { (snapshot) in
let value = snapshot.value as? NSDictionary
if(value != nil){
for i in value!{
let j = i.value as? NSDictionary
let precio = j?["precio"] as? Float
let fecha = j?["Fecha"] as? String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM d, yyyy"
let date = dateFormatter.date(from: fecha!)
if(((date?.timeIntervalSinceNow)! * -1) < (30*24*3600)){
print("Total:" ,total)
total += precio!
}
}
}
print("Calculing in the function", total)
}
return total
}
哪个在另一个视图控制器中的覆盖函数中调用,并且日志显示在viewdidload的打印中为0,但是在函数print中显示为30,但始终返回0,我相信问题是它在进入观察者之前返回了,但是我不确定对此是否有解决方案?
override func viewDidLoad() {
super.viewDidLoad()
nomUser.text = id?.displayName!
correoLabel.text = id?.email!
print("Calculing in View Controller", calculo.calculaBenef(), calculo.calculaGastos())
gastosField.text = String(calculo.calculaGastos())
benefField.text = String(calculo.calculaBenef())
// Do any additional setup after loading the view.
}
这是我的日志: Log
答案 0 :(得分:1)
在我目前正在使用的应用程序中,我遇到了类似的问题。解决方案是在功能中实现一个调度组。我还更改了函数返回total
的方式,以便现在由完成处理程序返回。
尝试以下方法:
func calculaGastos(completionHandler: @escaping (Float) -> Void){
let idUser = Auth.auth().currentUser?.displayName
var total : Float = 0
let ref = Database.database().reference().child("Users").child(idUser!).child("Gastos")
ref.observeSingleEvent(of: .value) { (snapshot) in
let value = snapshot.value as? NSDictionary
if(value != nil){
let myGroup = DispatchGroup()
for i in value!{
myGroup.enter()
let j = i.value as? NSDictionary
let precio = j?["precio"] as? Float
let fecha = j?["Fecha"] as? String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM d, yyyy"
let date = dateFormatter.date(from: fecha!)
if(((date?.timeIntervalSinceNow)! * -1) < (30*24*3600)){
print("Total:" ,total)
total += precio!
}
myGroup.leave()
}
myGroup.notify(queue: .main) {
print("Calculing in the function", total)
completionHandler(total)
}
}}
}
调用函数并像这样使用total
:
override func viewDidLoad() {
super.viewDidLoad()
nomUser.text = id?.displayName!
correoLabel.text = id?.email!
print("Calculing in View Controller", calculo.calculaBenef())
calculo.calculaGastos { (total) in
print("calculaGastos total: \(total)")
gastosField.text = String(total)
benefField.text = String(calculo.calculaBenef())
}
// Do any additional setup after loading the view.
}
据我了解:
observeSingleEvent
是异步的,因此它可能会在调用return
时完成。此外,for i in value
仅在observeSingleEvent
完成后才开始,因此return
在任务完成之前更有可能被调用。就是DispatchGroup()
和完成处理程序进入的地方。
调用myGroup.enter()
时,它通知DispatchGroup任务已开始。调用myGroup.leave()
时,会通知DispatchGroup该任务已完成。一旦.leave()
个与.enter()
个一样多,该组就结束了。然后myGroup
通知主队列该组已完成,然后调用completionHandler
并返回合计。
由于您使用calculaGastos
的方式,complementHandler也很有用。您正在调用该函数,然后使用返回值显示在textField中。现在添加了完成处理程序,textField.text
仅在calculaGastos
完成并返回total
后才设置:
calculo.calculaGastos { (total) in
print("calculaGastos total: \(total)")
gastosField.text = String(total)
benefField.text = String(calculo.calculaBenef())
}
希望有些道理!高兴的代码为您工作。