Reputation: 29
my friend and I are working on an IOS project on swift with (the new) Firebase integrated. We were able to write to the Firebase database, but we ran into problems in retrieve the data.
We have a tableView controller and we wish to populate the table from the Firebase database. Our database is organized like this:
root
|
- Movies
|__ -Wjdkfdmlksdf (unique ID made by Firebase)
|
|_Actors
|_A1 = ajkdfnadfdf
|_A2 = podifpadsfipasdip
|_Title = "Mission Impossible"
|_DirectedBy = "Christopher McQuarrie"
-Actors
|_ -ajkdfnadfdf (unique ID made by Firebase)
|_name : "Tom Cruise"
|_Birthday: xx/yy/zz
In the project, we made a file/class, which has methods that writes to and retrieves from firebase. If we want to retrieve information from Firebase for a particular view controller, we just call a particular method from that class.
For example, this is one of the methods in the class:
func getListOfAllMovieIDs() -> [String] {
let ref = FIRDatabase.database().reference();
var ListOfMovieIDS = [String]();
ref.child("Movies").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
let postDict = snapshot.value as! [String : AnyObject]
for (MID, _) in postDict {
ListOfMovieIDS.append(MID);
}
}) { (error) in
print(error.localizedDescription)
}
return listOfMoviesIDS
}
we call this method that I just described above in the viewDidLoad()
in the tableViewController
. However, the method returns nothing. We also called another methods like to get the list of unique IDS for actors and that returns nothing either. Any suggestion?
Upvotes: 2
Views: 3910
Reputation: 352
You can fetch all Movie IDs from your database just by updating following function as below:
func getListOfAllMovieIDs() -> [String] {
let ref = FIRDatabase.database().reference();
var ListOfMovieIDS = [String]();
ref.child("Movies").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
let postDict = snapshot.children.allObjects as? [DataSnapshot] {
for (index ,movieDict) in postDict.enumerated() {
let movieID = movieDict.key
ListOfMovieIDS.append(movieID);
}
}) { (error) in
print(error.localizedDescription)
}
return ListOfMovieIDS
}
Upvotes: 0
Reputation: 599491
Firebase loads data asynchronously. So instead of firing a request and waiting for a response, you send a request and then at some point will be notified of the response.
You can easily see this if you put some well placed logging statements in your code:
func getListOfAllMovieIDs() {
let ref = FIRDatabase.database().reference();
print("Before listener");
ref.child("Movies").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
print("Inside block");
})
print("After listener");
}
The order of the print statements will be:
Before listener
After listener
Inside block
So by the time your function exits, the data isn't available yet. This is not a mistake, but a very intentional choice. By allowing the code to continue, the app stays responsive for your users. Most of the modern internet works with this model, so it's typically best to embrace it (although it's tricky to get the hang of initially).
The solution is usually to rephrase your code. Instead of saying "first we load the data, then we do xyz", say it as "we start loading the data, once we get it we do xyz". This is why the Firebase data loading methods take a block: this contains the "xyz" that should happen once the data is available.
A nice side-effect of this is that this logic also works great for data that may be updated after you initially loaded it. When you use objectEventOfType()
, you can easily handle situations as "start synchronizing the data, whenever we get the data do xyz" and have an app that handles realtime updates.
Upvotes: 4
Reputation: 2914
Try using below method, because when you use observeSingleEventOfType
method; the block is immediately canceled after the initial data is returned. That might be the reason you are not able to see the results in callback block.
ref.observeEventType(.Value, withBlock: { snapshot in
println(snapshot.value)
}, withCancelBlock: { error in
println(error.description)
})
Upvotes: 0