How can I save an array using Parse? - ios

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.

Related

Realm Results To Array In Kii

am using Realm as a local store. I am currently trying to get the objects found in a realm Query (RLMResults) and store them in an array as part of a KiiObject.
I have very little experience using NSArray or NSDictionary to create an array of JSON to store in the KiiObject. As the number of objects in the realm search will vary i thought this might work:
for (RLMObject *object in currentEventResults) {
[array addObject:object];
}
and then add the array to my KiiObject.
[object setObject:array forKey:#"arryofObj"];
But the array has no objects in it when saved to Kii, but i know currentEventResults has 45 objects.
After a night of tinkering came up with this:
for (RLMObject *object in currentEvent) {
NSDictionary *dictOBJ =
#{#"eventID":[object objectForKeyedSubscript:#"eventID"],
#"longValue":[object objectForKeyedSubscript:#"longValue"],
#"latValue":[object objectForKeyedSubscript:#"latValue"],
#"pingTime":[object objectForKeyedSubscript:#"pingTime"]};
[mutableArray addObject:dictOBJ];
}
I then :
NSArray *arrayToSave = [mutableArray copy];
I then save the array to my Kii Object.
It works well. If there is a better solution please post it.

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.

Realm retrieving specific data

Good Day! I started using Realm.io Database for iOS 3 days ago. I can store data from the app to the database. But Retrieving it gives me headache. My problem is i cannot select specific data on database. I'm using this to get the data
RLMResults *data = [MapLocationCoordinates allObjects];
NSString *rawData = [NSString stringWithFormat:#"%#",[data objectAtIndex:0]];
NSLog(#"%#",rawData);
Now the result:
2015-05-07 05:31:01.554 Sample App[2401:79922] MapLocationCoordinates {
objectId = k0zpFLr5Un;
fName = George;
fLatitude = 11.985050;
fLongitude = 121.925295;
}
How can i get the specific data i want? For example, the fName and objectId
Thanks for your answers! More power!
RLMResults has many similar methods as NSArray and in some cases can be treated as such. For example, you can get the first object in the RLMResults using the -firstObject method.
In your code:
MapLocationCoordinates *coords = [data firstObject];
NSString *fName = [coords fName];
NSString *objectId = [coords objectId];
You can also iterate over an RLMResults collection in the same way as you would an array with for(id obj in collection){}.

Multiple image in parse relationship

i'm trying to create relationship between multiple images to an object. I keep getting following error:
errorcode
All objects in a relation must have object ids
What am i doing wrong? i've tried to follow documentation and adjust it to my example.
relationship code.
homeObject = [PFObject objectWithClassName:#"Homes"];
homeObject[#"userId"] = [PFUser currentUser].objectId;
for (int i = 0; i < [self.assets count]; i++) {
PFObject *object = [PFObject objectWithClassName:#"homeImages"];
ALAsset *asset = [self.assets objectAtIndex:i];
ALAssetRepresentation *representation = asset.defaultRepresentation;
UIImage *fullResolutionImage =
[UIImage imageWithCGImage:representation.fullResolutionImage
scale:1.0f
orientation:(UIImageOrientation)representation.orientation];
NSData *imgData= UIImageJPEGRepresentation(fullResolutionImage,0.0);
PFFile *imageFile = [PFFile fileWithName:#"Image.jpg" data:imgData];
object[#"Image"] = imageFile;
[object saveInBackground];
PFRelation *relation = [homeObject relationforKey:#"imageId"];
[relation addObject:object];
}
[homeObject saveInBackground];
You need to save the file and wait for it to finish saving (in the background), then you can safely attach it to your homeImages object. Next you need to save that object and wait for it to finish saving (in the background), then you can finally add it to the relation and save the parent object.
Since there's no in-built promises support (there are some 3rd party ones you might want to look at), you'll have to use nesting.
Consider creating an array of PFFile objects and using saveAllInBackground:block:. In the block create the homeImages objects and put them in an array, calling save-all again. Lastly in that completion block add them all to the relation and call saveInBackground on your homeObject.

Parse - saving related objects

I'm using Parse for the back end in my project.
As you would imagine there are quite a few relations in the data model. A lot of the time I create a "parent" object and all of its "children" at the same moment and save them all to Parse.
Now, when doing this is it necessary to save the children individually? The same for files etc...
First example - Adding an avatar to a user object
UIImage *image = // image from camera
NSData *pngData = UIImagePNGRepresentation(image);
PFFile *imageFile = [PFFile fileWithData:pngData];
[[PFUser currentUser] setObject:imageFile forKey:"avatar"];
OK, so on the device I can reference the #"avatar" key on the user and get the avatar file. But how should this be saved to Parse?
If I do...
[[PFUser currentUser] saveInBackground];
Will this save the new file that was added? Or do I need to save the file first and wait for this to succeed before then adding it into the user object and then saving the user object?
Second example
Creating a tree of objects...
PFObject *family = [PFObject objectWithClassName:#"Family"];
[family setObject:#"Smith" forKey:#"familyName"];
PFObject *person1 = [PFObject objectWithClassName:#"Person"];
[person1 setObject:#"Bob" forKey:#"name"];
PFObject *person2 = [PFObject objectWithClassName:#"Person"];
[person2 setObject:#"Alice" forKey:#"name"];
PFObject *person3 = [PFObject objectWithClassName:#"Person"];
[person3 setObject:#"Chris" forKey:#"name"];
[family setObject:#[person1, person2, person3] forKey:#"members"];
How would I save this collection of objects?
Can I just do [family saveInBackground];?
Or do I have to go through a process of saving every Person object first and checking that it worked before saving the family object?
As long as the relationship between parent and child is Pointer, you don't have to save the child first. PFRelation works differently, but a save on the parent object will also save children related as pointers. This is true for Cloud Code, and I am pretty sure it holds true for the device as well.
Some details in this answer: https://www.parse.com/questions/cloud-code-efficient-hierarchy-saving
Yes that will do...in fact there is a wide range of methods for saving the contents
Saving an Object to Parse
– save
– save:
– saveInBackground
– saveInBackgroundWithBlock:
– saveInBackgroundWithTarget:selector:
– saveEventually
– saveEventually:
Saving Many Objects to Parse
+ saveAll:
+ saveAll:error:
+ saveAllInBackground:
+ saveAllInBackground:block:
+ saveAllInBackground:target:selector:
Refer Here for more

Resources