Checking the contents of a Firebase/Realtime Database - ios

I am using the following code to check for new contents in Firebase / Database.
It is basically working. But when the contents is empty the code crashes.
What is the proper way to handle the case where postDict is coming back empty?
Is there some error code that we can be checked.
I have tried to check the value of postDict.count, but with no result.
FIRDatabaseHandle resultHandle =
[dbRef observeEventType:FIRDataEventTypeValue
withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSDictionary *postDict = snapshot.value;
NSManagedObject *artWorkRcd;
for (NSString* artKey in postDict) {
// Some useful code.
.......
}
}];

FIRDataSnapshot has a method called exists that returns YES if there is actually data in the snapshot. You should check this before using snapshot.value.

Related

Issue retrieving data from firebase database ios

At the moment I have an app that is using Firebase database to store the users:
Name
School
Subject
Within three separate textfields.
Right now I've managed to allow the user to enter his details within these three text fields and hit a button labeled update, which then sends the data to my firebase console.
This means that the user can enter their details, hit update and see them while they are logged in. however as soon as they logout and login again the textfields are blank, despite the fact that firebase has the info stored on its server.
I've been playing around all day trying to get it to work but to no avail.
Here we have the firebase reference and auth:
self.rootRef = [[FIRDatabase database] reference];
self.user = [FIRAuth auth].currentUser;
And the update button code that sends the users info to the firebase database:
- (IBAction)didTapEditProfile:(id)sender {
if (![_textFieldOne.text isEqual: #""]) {
NSString *item = _textFieldOne.text;
[[[[_rootRef child:#"users"] child:_user.uid] child:#"Name"] setValue:item];
}
if (![_textFieldTwo.text isEqual: #""]) {
NSString *itemTwo = _textFieldTwo.text;
[[[[_rootRef child:#"users"] child:_user.uid] child:#"School"] setValue:itemTwo];
}
if (![_textFieldThree.text isEqual: #""]) {
NSString *itemThree = _textFieldThree.text;
[[[[_rootRef child:#"users"] child:_user.uid] child:#"Subject"] setValue:itemThree];
}
}
The problem i'm having is with retrieving the data within the code below which is situated in the viewDidAppear:
[[_rootRef child:#"users"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSDictionary *usersDict = snapshot.value;
NSLog(#"%#",usersDict);
[usersDict objectForKey:_user.uid];
//I've tried numerous solutions here to get the text fields to display the info from the database
mainly:
NSString *field;
field = _textFieldOne.text;
field = [userDict objectForKey #"Name"];
The code i'm attempting to translate from looks like this:
field(userDict?.objectForKey("Name") as? String)
}];
Any ideas?
I managed to get everything sorted as follows:
-(void)configure:(NSString *)field {
_textFieldOne.text = field;
}
and then within the code I was having the problem:
[[_rootRef child:#"users"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSDictionary *usersDict = snapshot.value;
NSLog(#"%#",usersDict);
[usersDict objectForKey:_user.uid];
[self configure:[userDict objectForKey:#"Name"]];
}];
Thanks for the help.
Hey Joshua I have implemented the firebase and successfully retrieve the data from the firebase but the problem is i have implemented that in swift... here is my actual code if this helps you......
**rootRef.queryOrderedByChild("search what you want like specific name etc etc").observeEventType(.ChildAdded, withBlock: { snapshot in
if snapshot.value is NSNull {
print("the chat model is null")
SVProgressHUD.dismiss()
SVProgressHUD.showErrorWithStatus("No messages")
}
else {
print(snapshot) }**
Or if you want to fetch the whole database JSON here is the query
**rootref.observeEventType(.ChildAdded) { (snapshot: FDataSnapshot!) in
// 3
let id = snapshot.value["senderId"] as! String
let text = snapshot.value["text"] as! String
// 4
self.addMessage(id, text: text)
// 5
self.finishReceivingMessage()
}**
Here is a nice tutorial on this
https://www.raywenderlich.com/122148/firebase-tutorial-real-time-chat
If you want this to convert in objective-c then of course I will help you

Firebase inconsistent data structure

I am assessing Firebase as a replacement for Parse in my current app. However I have come across an issue when querying remote data.
When I retrieve a query I am getting an inconsistent data structure back.
My realtime data looks like this:
Previously in Parse the Bool values set up for 'Beef, chicken, pork' would have just been held in an array and I would query based on the array containing that item for each row. However as Firebase advises Arrays are bad in JSON I have had to implement them as Bool's and query based on they property, so my query looks like this
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
FIRDatabaseReference *path = [ref child:#"recipes"];
FIRDatabaseQuery *query1 = [path queryOrderedByChild:#"beef"];
FIRDatabaseQuery *query2 = [query1 queryEqualToValue:[NSNumber numberWithBool:YES]];
[query2 observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
[self hideSpinner];
NSArray *recipes = (NSArray *)snapshot.value;
The initial query works fine and the data comes back as follows
However, if I amend the query to :
[path queryOrderedByChild:#"pork"];
The data structure is completely different,
yet it comes from exactly the same json as the previous entry - has anyone experienced anything similar? its driving me nuts

Check if record exists in Firebase [duplicate]

This question already has an answer here:
Querying for existing nodes in Firebase is returning null
(1 answer)
Closed 6 years ago.
I am trying to understand how i can do a search in my Firebase database to check if a record exists and if so to grab details under that specific branch.
Currently i can accomplish what i need to by grabbing a specific record and placing it into a textfield and going from there, however i need to do a check on multiple records in the database till a specific record is found and from there load all the details under that branch.
Heres what i am doing currently;
Firebase *ref = [[Firebase alloc] initWithUrl: #"https://sizzling-inferno-255.firebaseio.com/"];
//Refer to users entity
Firebase *usersRef = [ref childByAppendingPath: #"id/"];
// Read data and react to changes
[usersRef observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
NSLog(#"%# -> %#", snapshot.key, snapshot.value);
NSDictionary *dict=[NSDictionary dictionaryWithDictionary:snapshot.value];
NSString *stri=[NSString stringWithFormat:#"%#",dict];
_textview1.text = stri;
string1 = snapshot.key;
_label1.text = string1;
}];
Feel free to check for yourself using the URL, i only use this for testing anyway.
I found something close to what i need however it is not in Objective C.
I'm new in firebase, but I've been working too much on the new version.
Is Record the name of your key inside of sizzling-inferno-255? So if it is. In this new version you can retrieve some info by:
FIRDatabaseReference *usersRef = [[FIRDatabase database] reference];
[[[[usersRef child:#"results"] child:#"sizzleing-inferno-255"] child:#"record"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSString *record = snapshot.value;
if(record.length > 0) {
// Yes! there is a record.
}
}
Is that what you want? Let me know.

Firebase on ios is slow in retrieving data

I've read that it's important to keep data flatter for Firebase and to also only nest data that you intend to call. I've done those things, but Firebase is still too slow at retrieving data. Here's an example:
My data looks like this:
--English
----Ari : 4
----Philip : 2
----John : 6
And my code looks like this:
[super viewDidLoad];
[[DataSource sharedInstance].selectedLanguageMutableArray removeAllObjects];
//Retrieving Data From Firebase
NSString* selectedLanguagePath = [NSString stringWithFormat:#"languages/%#", [DataSource sharedInstance].languageSelected];
Firebase *languagesRef = [[DataSource sharedInstance].ref childByAppendingPath:selectedLanguagePath];
[[languagesRef queryOrderedByValue] observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
[self.distanceMutableArray addObject:snapshot.key];
NSLog(#"%#", snapshot.key);
NSLog(#"%#", snapshot.value);
NSLog(#"%#", self.distanceMutableArray);
}];
//Selected Languages Mutable Array
[[DataSource sharedInstance].selectedLanguageMutableArray removeAllObjects];
for (NSInteger i = 0; i < self.distanceMutableArray.count; i++) {
UserCustomizationData *item = [[UserCustomizationData alloc] init];
NSString* selectedUser = self.distanceMutableArray[i];
Firebase* selectedUserRef = [[DataSource sharedInstance].usersRef childByAppendingPath:selectedUser];
if (selectedUser.length > 0) {
Firebase* profilePicRef = [selectedUserRef childByAppendingPath:#"profilePicture"];
[profilePicRef observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
NSString* profPicString = snapshot.value;
NSData *dataFromBase64=[NSData base64DataFromString:profPicString];
UIImage *profPicImage = [[UIImage alloc]initWithData:dataFromBase64];
item.profilePicture = profPicImage;
}];
[[DataSource sharedInstance].selectedLanguageMutableArray addObject:item];
}
}
However, the for loop runs before the self.distanceMutableArray can populate. This throws everything off because the for loop relies on the self.distanceMutableArray being populated.
Is there a way to retrieve data such that the code will run fluidly and in the order that it is written?
The issue here is that Firebase works via asynchronous calls; your code will not work consistently because the code below the Firebase block may be called before the block completes.
You will need to start coding asynchronously and only perform actions on snapshot data after you know for sure it has been populated (inside the block)
[[languagesRef queryOrderedByValue] observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
//at this point, firebase has loaded the snapshot
// so its available to work with
[self.distanceMutableArray addObject:snapshot.key];
for (NSInteger i = 0; i < self.distanceMutableArray.count; i++) {
//do some stuff with the items in snapshot
}
}];
//don't work with anything that was from the snapshot as it may have not been filled yet
However there's an issue as the code is using childAdded, so that will iterate over each item in the firebase node, so that code won't work either as it won't load the array correctly (yes we can fix that by populating the array during each loop).
The additional challenge here is that you need to retrieve data from Firebase based on the result of your first snapshot. Again, same situation exists; only perform actions on that retrieved data after you know for sure it has been retrieved.
One solution is to load in the entire dataset at one time and iterate over it (by value instead of added). If your data sets are smaller that works. However, for big datasets that can be too much.
[[languagesRef queryOrderedByValue] observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
//at this point, firebase has loaded the snapshot
// so its available to work with and loaded with
//everything in the node
for ( FDataSnapshot *child in snapshot.children) {
NSDictionary *dict = child.value;
NSString *uid = child.key;
[self.distanceMutableArray addObject:uid];
}
// now the array is loaded do something with it
}];
Another option is to change how your data is stored in firebase so you can retrieve data together so you dont have to make multiple observe calls.

How can I save an array using Parse?

I am struggling to use Parse to save an array of data - or at least I am finding I can't verify that my data is being saved.
I have a PFObject (journey) and I want to update it with my location (a string in the format: #"{lat, long}").
Eventually though I want to update and save my location every 10-30 seconds meaning I don't want to create a new object each time rather I want to add an array to the object and then update the array each time I have a new location.
Currently my code looks like this:
- (IBAction)startJourneyButtonPressed:(id)sender {
PFObject * journey = [PFObject objectWithClassName:#"Journey"];
journey[#"company"] = _companyNameTextField.text;
journey[#"destination"] = _destinationTextField.text;
[journey saveInBackground];
NSData * faceImageData = UIImagePNGRepresentation([_faceButton imageForState:UIControlStateNormal]);
PFFile * faceImageFile = [PFFile fileWithName:#"faceImage.png" data:faceImageData];
[faceImageFile saveInBackground];
NSData * carImageData = UIImagePNGRepresentation([_carButton2 imageForState:UIControlStateNormal]);
PFFile * carImageFile = [PFFile fileWithName:#"carImage.png" data:carImageData];
[carImageFile saveInBackground];
journey[#"faceImage"] = faceImageFile;
journey[#"carImage"] = carImageFile;
[journey saveInBackground];
NSMutableArray * locationArray = [NSMutableArray new];
[locationArray addObject:[self getCurrentLocationString]];
journey[#"location"] = locationArray;
[journey saveInBackground];
}
The strings are saving fine and so are the images but the dataBase doesn't seem to be getting uploaded with the array.
Here is a screenshot of my database:
I am expecting to see a "location" heading but obviously it isn't appearing.
Reading up on other forums it says that I have to have an object in JSON format for this to work but as I am only storing Strings and I am not receiving and JSON errors I don't think this is the issue.
Any help would be very appreciated
Probably it is saving your array, you should just manually in your database add column with name "location" (do not forget to set it as array type) to see the values.

Resources