如何在函数内部向字典添加值(使用Firebase)

时间:2017-07-12 03:21:10

标签: swift dictionary firebase firebase-realtime-database firebase-authentication

我在类文件中声明了一个字典,如下所示:

var myDict: [Int: String] = [:]

我还创建了一个更改字典中值的函数:

func firebaseToDictionary() {
    let uid = FIRAuth.auth()?.currentUser?.uid
    let infoRef = FIRDatabase.database().reference().child("users").child(uid!).child("info")

    infoRef.observe(FIRDataEventType.value, with: { (snapshot) in
        let postDict = snapshot.value as? [String: String]
        for item in postDict! {

            let theString = item.value["FirebaseString"]
            let theNumber = item.value["FirebaseInt"]                

            self.myDict[theNumber] = theString

            //First Print
            print(myDict)
        }
    })
    //Second Print
    print(myDict)
}

//First Print,字典包含新值并且看起来很好,但是//Second Print显示了创建的字典;为[:]//Second Print实际显示在//First Print

之前的终端中

为什么我的字典仍然显示为[:],即使我在函数内部更改了它?

2 个答案:

答案 0 :(得分:1)

从您的代码看来infoRef.observe()似乎是一个异步任务,因此如果您之后有一个代码,它可能会在异步任务执行之前执行。您可以按如下方式更改代码:

func firebaseToDictionary() {
    let uid = FIRAuth.auth()?.currentUser?.uid
    let infoRef = FIRDatabase.database().reference().child("users").child(uid!).child("info")

    infoRef.observe(FIRDataEventType.value, with: { (snapshot) in
        let postDict = snapshot.value as? [String: String]
        for item in postDict! {

            let theString = item.value["FirebaseString"]
            let theNumber = item.value["FirebaseInt"]                

            self.myDict[theNumber] = theString

            //First Print
            print(myDict)
            DispatchQueue.main.async {
               tableView.reloadData()
            }
        }
    })
}

观察后添加的任何内容都可以立即执行,而无需等待观察部分完成。因此,请确保在完成之后是否要执行某些操作,请在块内执行。

答案 1 :(得分:1)

您的代码工作正确。你有一个同步函数,它在后台线程中获取数据

infoRef.observe(FIRDataEventType.value, with: { (snapshot) in
    let postDict = snapshot.value as? [String: String]
    for item in postDict! {

        let theString = item.value["FirebaseString"]
        let theNumber = item.value["FirebaseInt"]                

        self.myDict[theNumber] = theString

        //First Print
        print(myDict)
    }
})

从远程数据库接收数据后,将调用此闭包内的代码。因此,如果您在此异步调用之后有另一个print(myDict),它将首先打印出来,其中包含原始值。然后,当异步调用完成并且闭包内的代码被执行时,第一个print(myDict)被触发,然后使用新更新的数据

话虽这么说,你的新数组在回调你的闭包之前没有加载数据。从您的代码中,您似乎有一个显示此数组的数据库的表视图。所以你必须等到数组获取数据然后重新加载表视图。所以你需要将代码带到闭包的末尾。但是,在swift中,您无法直接从后端线程更新UIElement,就像这个回调函数一样。因此,在填充数组之后,需要以这种方式在主线程中运行表视图重新加载代码

infoRef.observe(FIRDataEventType.value, with: { (snapshot) in
    let postDict = snapshot.value as? [String: String]
    for item in postDict! {

        let theString = item.value["FirebaseString"]
        let theNumber = item.value["FirebaseInt"]                

        self.myDict[theNumber] = theString

        //First Print
        print(myDict)
        DispatchQueue.main.async {
           tableView.reloadData()
        }
    }
})