1

I was trying to retrieve data from firebase and return the data by using completionHandler. However, the completionHandler returned only part of the data from my Firebase. Thus, I used a global variable merged_spendDict to store data from Firebase. However, merged_spendDict was empty.

Question 1: How can I retrieve the whole data before I return it in the completionHandler? Question 2: Why is the merged_spendDict empty after I update it? I know retrieving data is asynchronous. How can I retrieve the whole data and save them all in a global variable?

The whole data should look like:

["02-09-2018": ["9"], "02-03-2018": ["3"], "02-06-2018": ["6"], "02-02-2018": ["2"], "02-10-2018": ["10"], "02-08-2018": ["8", "88"], "02-01-2018": ["1"], "02-05-2018": ["5"], "02-07-2018": ["7"]]

My output is

merged_spendDict:  [:] // How to store data from Firebase to a global variable?
dictionary in ViewDidload ["02-07-2018": ["7"]]
spendDict in closure  ["02-07-2018": ["7"]]
dictionary in ViewDidload ["02-06-2018": ["6"]]
spendDict in closure  ["02-06-2018": ["6"]]
dictionary in ViewDidload ["02-05-2018": ["5"]]
spendDict in closure  ["02-05-2018": ["5"]]
dictionary in ViewDidload ["02-08-2018": ["8"]]
spendDict in closure  ["02-08-2018": ["8"]]
dictionary in ViewDidload ["02-09-2018": ["9"]]
spendDict in closure  ["02-09-2018": ["9"]]
dictionary in ViewDidload ["02-01-2018": ["1"]]
spendDict in closure  ["02-01-2018": ["1"]]
dictionary in ViewDidload ["02-02-2018": ["2"]]
spendDict in closure  ["02-02-2018": ["2"]]
dictionary in ViewDidload ["02-03-2018": ["3"]]
spendDict in closure  ["02-03-2018": ["3"]]
dictionary in ViewDidload ["02-08-2018": ["88"]]
spendDict in closure  ["02-08-2018": ["88"]]
dictionary in ViewDidload ["02-10-2018": ["10"]]
spendDict in closure  ["02-10-2018": ["10"]]

Here is my code:

var merged_spendDict : [String:[String]] = [:]
    typealias spendClosure = (Dictionary<String,[String]>?) -> Void
    @IBOutlet weak var passMonth: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()

//        retrieveSpend(completionHandler: spendClosure)

        retrieveSpend(){
            dict in

            self.merged_spendDict.update(other: dict)
            print("dictionary in ViewDidload", dict)

        }

        print("merged_spendDict: ",self.merged_spendDict)


    }

func retrieveSpend(completionHandler: @escaping ([String:[String]])->()){
        // the dict will be [time:[amount , amount , amount]]

         var spendDict :[String: [String]] = [:]
         let spendDB = Database.database().reference().child("Spend")
         spendDB.observe(.childAdded, with:{(snapshot) in
            spendDict.removeAll()
            let returnValue = snapshot.value as! Dictionary<String, String>
            var amount_retrieved = returnValue["amount"]
            var time_retrieved = returnValue["time"]
            var tag_retrieved = returnValue["tag"]

            if spendDict.index(forKey: time_retrieved!) == nil {
                // the key does not exist in the dictionary

                spendDict[time_retrieved!] = [amount_retrieved!]
            }
            else{
                spendDict[time_retrieved!]?.append(amount_retrieved!)
            }

            completionHandler(spendDict)
            print("spendDict in closure ", spendDict)

        })



    }

Please help me. Thanks.

FYY
  • 37
  • 6
  • It seems like you might be confused about how asynchronous programming works. Luckily, Doug Stevenson just made a great article about it that I suggest you check out: https://medium.com/google-developers/why-are-firebase-apis-asynchronous-callbacks-promises-tasks-e037a6654a93 – Jen Person Feb 16 '18 at 18:03

0 Answers0