如何修复Firebase的异步问题 [英] How to fix the async issue of firebase

查看:78
本文介绍了如何修复Firebase的异步问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试查询数据并将其更新到Firebase.但是我无法获取数据.似乎程序没有遇到ref.observeSingleEvent 我该怎么做才能解决此问题?

Im trying to query and update data to firebase. But I cannot get the data. It seems the program doesn't run into ref.observeSingleEvent what should I do to fix this?

    func getId(path:String, value:String?, completion: @escaping (String?) -> Void) {

        let ref = Database.database().reference(withPath: path).queryOrdered(byChild: "name").queryEqual(toValue: value)

        ref.observeSingleEvent(of: .childAdded, with: { snapshot in
            print("running in getId")
            completion(snapshot.key)                

        }) { (error) in
            print(error.localizedDescription)
        }
    }
@objc func onTapConfirmed(){

     self.getId(path: "patients", value: self.kardex?.patient?.name) { snapshotKey in
      BookingViewController.kardexDict["patient"] = snapshotKey as AnyObject?

      print("1:get patient name")
      }

     self.getId(path: "nurses", value: BookingTreatmentListController.nurseName) { snapshotKey in
      BookingViewController.kardexDict["nurse"] = snapshotKey as AnyObject?
      print("2:get nurse name")
      }
      Database.database().reference().child("kardexes").child(BookingViewController.newKardex.id).updateChildValues(BookingViewController.kardexDict)

     print("save kardexDict")

 }

我希望得到以下结果

"1:获取患者姓名"->在getId中运行"-> "2:获取护士姓名"->在getId中运行"->保存kardexDict"

"1:get patient name" -> "running in getId" -> "2:get nurse name" -> "running in getId" -> "save kardexDict"

但是我得到了
"1:获取患者姓名"->"2:获取护士姓名"->保存kardexDict"

But I got
"1:get patient name" -> "2:get nurse name" -> "save kardexDict"

并且kardexDict中的数据不正确,因为该数据不是从函数getId()获得的 我该怎么做才能迫使程序按照我的预期进行.

and the data in kardexDict is not correct since the data is not obtained from function getId() What can I do to force the program follow my order I expected.

推荐答案

您使用Firebase的方式错误:

You are using firebase in the wrong way:

  • observeSingleEvent异步运行,因此事件的顺序为:在getId中运行"->"1:获取患者姓名"
  • updateChildValues通常会在任何observeSingleEvent完成之前被调用
  • observeSingleEvent runs asynchronously, so the order of events will be: "running in getId" -> "1:get patient name"
  • updateChildValues will typically called before any of the observeSingleEvent finishes

因此,在获得患者或护士姓名之前,您首先将空(?)kardexDict写到firebase.

Hence, you first write the empty(?) kardexDict to firebase, before you even get the patient or nurse name.

此外,请注意completion闭包未在主线程中运行.因此,您可能会观察到一些不可预测的并发问题/竞态条件. 您要做的就是等待所有observeSingleEvent完成,然后将数据写回.

Also, be aware the the completion closure does not run in the main thread. Therefore, you will likely observe some unpredictable concurrency issues / race conditions. What you have to do is, to wait for all observeSingleEvent to be finished, and then write the data back.

因此,您的想法 或多或少会像这样(可能无法完全编译,因为我没有运行您的环境):

So, an more or less 1-to-1 transfer of your idea could look like this (might not exactly compile, because I don't have your environment running):

func getId(path:String, value:String?, completion: @escaping (String?) -> Void) {

    let ref = Database.database().reference(withPath: path).queryOrdered(byChild: "name").queryEqual(toValue: value)

    ref.observeSingleEvent(of: .childAdded, with: { snapshot in
        print("running in getId")
        completion(snapshot.key)                

    }) { (error) in
        print(error.localizedDescription)
    }
}

@objc func onTapConfirmed(){

    let patientName = self.kardex?.patient?.name
    let nurseName = BookingTreatmentListController.nurseName
    self.getId(path: "patients", value: patientName) { snapshotKey in
        print("1:got patient")
        let patient = snapshotKey as AnyObject?
        self.getId(path: "nurses", value: nurseName) { snapshotKey in
            print("2:got nurse")
            let nurse = snapshotKey as AnyObject?
            DispatchQueue.Main.async {
                print("save kardexDict (in main thread!")
                BookingViewController.kardexDict["patient"] = patient
                BookingViewController.kardexDict["nurses"] = nurse
                let kardexes = Database.database().reference().child("kardexes")
                kardexes.child(BookingViewController.newKardex.id).updateChildValues(BookingViewController.kardexDict)
            }
        }
    }
}

尽管如此,它可能不是有效的,因为涉及到两个单独的网络呼叫(首先是患者,然后是护士).也许您最好使用observe而不是observeSingleEvent.

Nevertheless, it might not be that efficient, because there are two separate web calls involved (first the patients, then the nurses). Maybe you better use observe instead of observeSingleEvent.

这篇关于如何修复Firebase的异步问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆