如何解决Firebase的异步问题

时间:2019-07-31 08:54:48

标签: swift firebase firebase-realtime-database

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

    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:获取患者姓名”->“ 2:获取护士姓名”->“保存kardexDict”

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

1 个答案:

答案 0 :(得分:0)

您使用Firebase的方式错误:

  • observeSingleEvent异步运行,因此事件的顺序为:“在getId中运行”->“ 1:获取患者姓名”
  • updateChildValues通常会在任何observeSingleEvent完成之前被调用

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

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


更新

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

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