Как сделать наблюдение на данный момент в Swift? - PullRequest
1 голос
/ 30 апреля 2019

У меня есть проблема в этом коде:

    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.
}

Вот мойжурнал: журнал

1 Ответ

1 голос
/ 30 апреля 2019

В приложении, над которым я сейчас работаю, я столкнулся с похожей проблемой. Решение состояло в том, чтобы внедрить группу диспетчеризации в функцию. Я также изменил способ, которым ваша функция возвращает 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())
    }

Надеюсь, в этом есть какой-то смысл! Рад, что код работал для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...