Helleeni
Helleeni

Reputation: 15

Capturing Firebase realtime observeSingleEvent data fails on first call

I have a working connection to Firebase realtime database. The observeSingleEvent is triggered by IBAction button tapped. First call to fetch the data fails. Second push of the button fetches the data OK. What would be a way to get the data with the first call? I've tried calling observeSingleEvent several times, tapping the button programmatically and adding a wait to allow observeSingleEvent to complete. Even added the completion block when getting desperate. Any hint as what I am doing wrong would be highly appreciated.

--- EDIT ---

Fixed the code below as @rob suggested. Only addition to Rob's answer was that @escaping was needed in definition of completion block. Now works beautifully.

var prodNo: String = "XXX000000"
var productDataLocal: [String: String] = ["ProdNo": "", "Location": ""]

@IBAction func findTapped(_ sender: Any) {
        fetchFirebaseData { () -> () in
            if productDataLocal["ProdNo"] == prodNo {  // check that the data matches the product
                // launch a segue (that is detached from button)
                self.performSegue(withIdentifier: "moveToDetail", sender: nil)
            }
            else {
                showError("Product \(prodNo) can't be found.")
            }
        }
}   // findTapped

func fetchFirebaseData(completion: @escaping () -> ()) {  // --- EDIT ---@escaping addedd
    // check if this product can be found in Firebase!    
    self.ref.child("Id").child("\(prodNo)").observeSingleEvent(of: .value, with:
        { (snapshot) in
            // try if this product can be found in Firebase
            let tempData = snapshot.value as? Dictionary<String, Any>
            if let actualData = tempData {
                self.copyData(actualData)
            }
            completion()  // --- EDIT --- completion moved here
        })  { (error) in
            print(error.localizedDescription)
            completion()  // --- EDIT ---and completion moved here
            }
    // --- EDIT -- completion() removed from here
}  // fetchFirebaseData

func copyData(_ actualData: Dictionary<String, Any>) {
    dump(actualData)  // for debugging what "actualData" actually contains
                      // this is always OK when execution gets here
    self.productDataLocal["ProdNo"] = actualData["ProdNo"] as? String
    self.productDataLocal["Location"] = actualData["Location"] as? String
}

The dump of "actual" data works and produces correct data - when it gets executed. The problem is that I can't find any way to get this code to execute but pressing the button second time. (And yes the "ProdNo" is repeated in the JSON structure so that I can check that it matches the requested product number.) --- EDIT --- the code above now works and problem solved

▿ 2 key/value pairs
  ▿ (2 elements)
    - key: "ProdNo"
    - value: XXX000000 #0
      - super: NSMutableString
        - super: NSString
          - super: NSObject
  ▿ (2 elements)
    - key: "Location"
    - value: "Warehouse 1" #1
      - super: NSMutableString
        - super: NSString
          - super: NSObject

Upvotes: 1

Views: 179

Answers (1)

Rob C
Rob C

Reputation: 5073

You are calling you completion block synchronously. You should not be calling it until observeSingleEvent completes. If you move your completion block to your observeSingleEvent handler you should get the results you are looking for:

func fetchFirebaseData(completion: @escaping () -> ()) { // --- EDIT --- added "@escaping
    // check if this product can be found in Firebase!
    self.ref.child("Id").child("\(prodNo)").observeSingleEvent(of: .value, with: { (snapshot) in
            // try if this product can be found in Firebase
        let tempData = snapshot.value as? Dictionary<String, Any>
        if let actualData = tempData {
            self.copyData(actualData)
        }
        completion()
        }) { (error) in
            print(error.localizedDescription)
            completion()
        }
}  // fetchFirebaseData

Upvotes: 1

Related Questions