I am trying to fetch data from Firebase and add it as a object in a Swift array but whenever I run the application the array prints out empty. When I put a print statement inside the observe each purse prints out like I want it to but the purse never gets appended to the array.
var purses = [Purse]()
override func viewDidLoad() {
fetchPurse(completion: {print(self.purses.count)})
}
func fetchPurse(completion: @escaping () -> ()){
let ref = FIRDatabase.database().reference(fromURL: "https://test-database-ba3a2.firebaseio.com/")
let user = (FIRAuth.auth()?.currentUser?.uid)!
let userRef = ref.child("users").child(user).child("devices")
userRef.observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject]{
let purse = Purse()
purse.setValuesForKeys(dictionary)
self.purses.append(purse)
completion()
}
}, withCancel: nil)
}
This sounds like a misunderstanding of how async methods work.
If you use code like this:
//at this point purses is empty..
fetchPurse()
print("purses count = \(purses.count)")
You will always see an empty purses array.
The problem is that the fetchPurse() function uses the Firebase function observe, which is asynchronous. It requests that Firebase run the code you pass as your with: closure when a new entry is added. The observe function returns immediately, and invokes the closure you pass to it as some future time when FireBase adds a new child object.
As a result, your fetchPurse() function also returns before the new purse object is added to your array of purses.
As @DávidPásztor said in his comment, you should refactor fetchPurse to take a completion handler that gets called when the purses array is updated:
func fetchPurse(completion: () -> ){
let ref = FIRDatabase.database().reference(fromURL: "https://test-database-ba3a2.firebaseio.com/")
let user = (FIRAuth.auth()?.currentUser?.uid)!
let userRef = ref.child("users").child(user).child("devices")
userRef.observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject]{
let purse = Purse()
purse.setValuesForKeys(dictionary)
self.purses.append(purse)
//This is the new line that calls your new completion handler
completion()
}
}, withCancel: nil)
}
And then you'd call it like this:
fetchPurse(completion: {
print("purses count = \(purses.count)")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With