В приложении, над которым я сейчас работаю, я столкнулся с похожей проблемой. Решение состояло в том, чтобы внедрить группу диспетчеризации в функцию. Я также изменил способ, которым ваша функция возвращает 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
, который возвращает итоговое значение.
ЗавершениеHandler также полезно благодаря тому, как вы используете calculaGastos
. Вы вызываете функцию, а затем используете возвращаемое значение для отображения в textField. Теперь, когда обработчик завершения добавлен, textField.text
устанавливается только после завершения calculaGastos
и возвращает total
:
calculo.calculaGastos { (total) in
print("calculaGastos total: \(total)")
gastosField.text = String(total)
benefField.text = String(calculo.calculaBenef())
}
Надеюсь, в этом есть какой-то смысл! Рад, что код работал для вас.