printed result
["data1"]
["data1", "data2"]
["data1", "data2", "data3"]
...
wanted result is only the last printed array with all data or just getting that last array would help me out
["data1", "data2", "data3"]
here is the code I use to get the data from firebase
var dataArray = [String]()
func fetchFirebaseData(){
var datref: DatabaseReference!
datref = Database.database().reference()
datref.child("Data").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject]{
let data = SpeisekarteInfos(dictionary: dictionary)
data.setValuesForKeys(dictionary)
self.dataArray.append(data.Name!)
print(self.dataArray)
}
}, withCancel: nil)
}
You are observing .childAdded events, which will get called repeatedly, once for each entry in your database. I haven't used FireBase, but based on a little Googling it sounds like you should instead observe the .value event, and then refactor your code to expect all of them at once. Something like this:
var dataArray: [String]?
func fetchFirebaseData(){
dataArray = []
var datref: DatabaseReference!
datref = Database.database().reference()
datref.child("Data").observe(.value, with: { (snapshot) in
for item in snapshot.children {
if let dictionary = item as? [String: AnyObject]{
let data = SpeisekarteInfos(dictionary: dictionary)
data.setValuesForKeys(dictionary)
self.dataArray.append(data.Name!)
}
}
print(self.dataArray)
}, withCancel: nil)
}
I'm doing some guesswork on the format of the data you get back from a .value call, so I'm not positive the above will work, but it should at least point you in the right direction.
Note that in my version we request everything at once with a .value observer, then loop through all the children returned, build them into an array, and only print the array once they're all returned.
From what I'm reading it looks like your .value observer will be called with all the elements every time the database is updated. If your database is dynamic this would not be a good approach.
Related
So I'm running into a problem where I can't seem to save the contents of a local array outside of a for loop. This code iterates through notifsTop (which is a dictionary) and saves the values into another array. However, outside of the for loop, the contents of tempnotifsarray are empty, which doesn't make sense to me since I appended them to an array that is outside of the loop block. I have been struggling with this for some time and can't figure out what is going on. Any help would be appreciated, thanks!
func createArray() -> [notificationLabel] {
let newUserInfo = Auth.auth().currentUser
let uid = newUserInfo?.uid
self.ref = Database.database().reference()
let practionerRef = self.ref.child("users").child(uid!)
var tempnotifsArray: [notificationLabel] = []
practionerRef.observeSingleEvent(of: .value, with: {(snapshot) in
let value = snapshot.value as? NSDictionary
if let notifsTop = value?["Notifications"] as? NSDictionary { //top of the notifications hierarchy
for (_, myValue) in notifsTop {
// Iterate in here
//self.notifications.append(myValue)
let notification = notificationLabel(label: myValue as! String)
tempnotifsArray.append(notification)
//if I print here the array is full with the values I want
}
}
})
print(tempnotifsArray) //comes out as []
return tempnotifsArray
}
I have places in different cities in my real time database (firebase).
Following is my database structure.
But according to firebase tutorial, I tried following code to get data
cityA.queryOrdered(byChild: "completed").observe(.value, with: { snapShot in
var newItems: [AttractionPlace] = []
for child in snapShot.children {
if let snapShot = child as? DataSnapshot,
let attraction = AttractionPlace(snapShot: snapShot) {
newItems.append(attraction)
}
}
print(newItems.count)
})
I also would like to get data from cityB at the SAME TIME and no idea how to retrieve. I know I can repeat same action to cityB. But is there any better way?
I'm not sure how you want your data structured. Can you show me what an AttractionPlace is supposed to look like? The code below does what you want appending the name of each place to newItems, but without specifying from which city it is. Take notice that I did not use your AttractionPlace object.
let dataref = Database.database().reference()
dataref.child("attractions").observe(.value, with: { (snapshot) in
var newItems = [AnyObject]()
for city in snapshot.children.allObjects as! [DataSnapshot] {
let value = city.value as? NSDictionary ?? [:]
for child in value {
let attraction = child.value
newItems.append(attraction as AnyObject)
}
}
print("newItems: ",newItems)
print("newItems.count: ",newItems.count)
})
Result:
newItems: [Place 3, Place 4, Place 1, Place 2]
newItems.count: 4
I am retrieving a snapshot of all of the users in my Firebase database. After I append all of my users from my "users" node of my database to an array of users , I attempt to print the user count (which should be 12) and it says it is 0 instead.
I added a breakpoint at the closing brace of the if-statement which shows to me that the user count reaches 12. However, by the time it comes time to print this number, it is zero. Stepping through a bunch of times is just a lot of assembly code that tells me nothing.
I call this function in the viewDidLoad() method and tried to print the users count after this function is called in addition to printing it within the function and it is still 0.
func getUsers() {
let ref = Database.database().reference().child("users")
ref.observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
user.id = snapshot.key
user.setValuesForKeys(dictionary)
self.users.append(user)
}
}, withCancel: nil)
print(users.count)
}
Here you go, a fix below. Like Ahmed is saying: it takes some time to get the data since it is async.
func getUsers(completionHandler:#escaping (Int) -> ()){
let ref = Database.database().reference().child("users")
ref.observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
user.id = snapshot.key
user.setValuesForKeys(dictionary)
self.users.append(user)
completionHandler(self.users.count)
}
})
override func viewDidLoad() {
super.viewDidLoad()
getUsers(){ (count) in
print(count)
}
}
It is pretty straightforward what is going on, I just added a completion handler.
Because observe work asynchronously, and you are printing users.count before updating users array...
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)")
}
I'm having a little trouble accessing and saving nested Firebase data.
Here is how my database is set up:
How would I get Bike and Popsicle into an array as well as getting country and price in 2 other arrays? I will be using these arrays to populate a TableView.
Try something like this:
let ref = FIRDatabase.database().reference().child("Test")
ref.observeSingleEvent(of: .value, with: { snapshot in
if let data = snapshot.value as? [String : [String : NSNumber]] {
let bikePopsicleArray = Array(data.keys)
let countryArray = [String]()
let pricesArray = [NSNumber]()
for (key, value) in data.values {
countryArray.append(key)
pricesArray.append(value)
}
}
})
Not sure if this will work but give it a try, let me know how it goes.