【问题标题】:How to make an observe at the moment in Swift?目前如何在 Swift 中进行观察?
【发布时间】:2019-09-19 09:05:53
【问题描述】:

这段代码有问题:

    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

【问题讨论】:

    标签: ios swift firebase firebase-realtime-database swift4


    【解决方案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()s 与.enter()s 一样多,该组就结束了。然后myGroup通知主队列组结束,然后调用completionHandler返回total。

    由于您使用calculaGastos 的方式,completionHandler 也很有用。您正在调用该函数,然后您将使用返回值显示在文本字段中。现在添加了完成处理程序,textField.text 仅在 calculaGastos 完成并返回 total 后设置:

    calculo.calculaGastos { (total) in
          print("calculaGastos total: \(total)")
             gastosField.text = String(total)
             benefField.text = String(calculo.calculaBenef())
        }
    

    希望这是有道理的!很高兴代码对你有用。

    【讨论】:

    • 感谢您的回答,您能否解释一下完成处理程序和调度组的作用,您为什么使用它?谢谢!
    • 很高兴它有帮助!我只是编辑了我的回复来解释一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-01
    • 2018-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多