我的代码有问题:
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
最佳答案
在我目前正在开发的一个应用程序中,我遇到了类似的问题。解决方案是在功能中实现一个调度组。我还更改了函数返回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
的方式,完成处理程序也很有用。您正在调用该函数,然后使用返回值显示在textField中。现在添加了完成处理程序,仅在textField.text
完成并返回calculaGastos
后才设置total
:calculo.calculaGastos { (total) in
print("calculaGastos total: \(total)")
gastosField.text = String(total)
benefField.text = String(calculo.calculaBenef())
}
希望有道理!高兴的代码为您工作。
关于ios - 目前如何在Swift中进行观察?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55925401/