PFQuery synchronous call works, asynchronous call fails - ios

I am new to using parse and experience some problems querying the data I have added in my parse class. My problem is that I can get the synchronous call ([query findObjects]) working, the asynchronous call ([queryInBackground...]) however fails.
Here are the two code snippets:
-(void)getAllDataFromParse{
//simple query works
PFQuery *query = [PFQuery queryWithClassName:#"wordsDB"];
[query setLimit: 1000];
NSArray *objects = [query findObjects];
}
//background query not working
PFQuery *queryInBackground = [PFQuery queryWithClassName:#"wordsDB"];
[queryInBackground findObjectsInBackgroundWithBlock:^(NSArray *objects2, NSError *error) {
if (!error) {
//query succeeds, do something
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
This method is called in my mainViewController, the call is at the end of the viewDidLoad function
[self performSelector:#selector(getAllDataFromParse)];
In debugging, the program reaches [queryInBackground findObjectsInBackgroundWithBlock.... ] but when executing it, it jumps straight to the end of the method.
There is no error message I can see. Can anyone tell me what is going wrong with my asynchronous call?
I have tried running it on emulator and real device.

This is an asynchronous call meaning that it will continue running in the background. It going to the end of the method is perfectly normal.
[queryInBackground findObjectsInBackgroundWithBlock:^(NSArray *objects2, NSError *error) {
if (!error) {
//query succeeds, do something
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
This may also help.

Related

Problems in calling Parse getdataInthebackground in a for loop

Hi I am trying to query some files from my Parse database and I want the files to be sorted according to the updateAt time. I have the following code. The query works and the results are sorted according to my condition, but when I load the files using getDataInBackground and then add to an array. The files are not sorted and they appear to be random in the array.
So My questions are
What can I do to make sure the files in the array are in the same order as the query results?
Any way to check the files/images against the objectID in the completion block of getDataInBackground?
p.s. I don't want to use getData since I don't want it to block the main thread.
Thank you very much in advance
PFQuery *query = [PFQuery queryWithClassName:#"Photo"];
[query orderByDescending:#"updateAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *photoStacks, NSError *error)
{
if (!error) {
// The find succeeded.
for (PFObject *photoImage in photoStacks) {
PFFile *userImageFile = photoImage[#"image"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
// need to check object id before adding into the stack to make sure the order is right
[photoImageStacks addObject:image];
if ([photoImageStacks count] == photoStacksCount)
{
[photoPile setArray:photoImageStacks];
}
}
}];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
use breakpoint and trace first photoImageStacks and second after response you should call reload method if you are using tableview or some delegate or fire a notification so that you can update ui accordingly after successful response.

How to get all Uses who is register in parse.. using PFInstallation in ios

I am using below code to fetch users but I am not able to get it.. app is crashes... Please help me to get all installation objects list..
PFQuery *userQuery = [PFQuery queryWithClassName:#"_Installation"];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
NSLog(#"objc...%#",objects);
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"id...%#",object.objectId);
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
Try this:
PFQuery *userQuery = [PFInstallation query];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
NSLog(#"objc...%#",objects);
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"id...%#",object.objectId);
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
FYI, Wain is correct in his comment that installations are not users. Are you sure this is the class you want to query?
With Parse, as flexible and sound it is, they are limitations to it. Some are extremely worrying in my opinion as a developer that uses Parse, and some are just implemented server side to protect your end-users. This is one, you can not query the Installation class from a client, the only columns you can query are listed in the API Reference . However, you can query the class through a cloud function using the master key, otherwise, you will have to use a pointer/relation to other tables for whatever data you want to retrieve. Additionally, for future question seekers, please refer to Wains note. It's a valid statement and should be considered prior to proceeding with anything. Users are not installations, the same 'user' i.e., device, can re-download the app multiple times creating numerous installations (not users).

Query PFUser not working

I am using this query to find users, it works but it just shows me the first user. I want it to show me the user with the text of an UITextField.
How can I do that ?
(I have a textfield and there I type in a name and then it should show the parsed users with the name)
PFQuery *query = [PFUser query];
NSArray *users = [query findObjects];
userQuerys.text = users[0][#"username"];
Thanks very much
This code will fetch you all the PFUsers in which username is equal to the name parameter:
- (void)searchUsersNamed:(NSString *)name withCompletion:(void (^)(NSArray *users))completionBlock {
PFQuery *query = [PFUser query];
[query whereKey:#"username" equalTo:name];
[query findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
// we found users with that username
// run the completion block with the users.
// making sure the completion block exists
if (completionBlock) {
completionBlock(users);
}
} else {
// log details of the failure
NSLog(#"Error: %# %#", error, [error description]);
}
}];
}
An example, if you need to update the UI with the result, for example, a table:
- (void)someMethod {
// we will grab a weak reference of self to perform
// work inside the completion block
__weak ThisViewController *weakSelf = self;
//replace ThisViewController with the correct self class
[self searchUsersNamed:#"Phillipp" withCompletion:^(NSArray *users) {
//perform non-UI related logic here.
//set the found users inside the array used by the
//tableView datasource. again, just an example.
weakSelf.users = users;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//pefrorm any UI updates only
//for example, update a table
[weakSelf.tableView reloadData];
}];
}];
}
A small note: the completionBlock here wont run if there is an error, but it will run even if no users were found, so you gotta treat that (if needed. in this example, it was not needed).
Avoid running non-UI related logic on that mainQueue method, you might lock the Main thread, and that`s bad user experience.

Variable set in code block does not retain its value

Newbie question... I am trying to set a variable self.projectName in a code block but when I call it outside the code block, the value is not retained. After reading more about code blocks, it seems like there are some rules on when values become available but I'm still not clear why I can't set the value for use later...any help would be much appreciated!
PFQuery *query = [PFQuery queryWithClassName:#"ScheduledProjects"];
[query findObjectsInBackgroundWithBlock:^(NSArray *projects, NSError *error) {
if (!error) {
PFObject *project = [projects objectAtIndex:indexPath.row];
self.projectName = project[#"name"];
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
NSLog (#"project name = %#",self.projectName);
The block is meant to be called asynchronously, which means that after you defined it you don't know exactly when it will finish executing.
To use the variable try creating a callback function and calling it at the end of the block. There you will know for sure that it has been executed.
Example:
-(void)yourMethod{
PFQuery *query = [PFQuery queryWithClassName:#"ScheduledProjects"];
[query findObjectsInBackgroundWithBlock:^(NSArray *projects, NSError *error) {
if (!error) {
PFObject *project = [projects objectAtIndex:indexPath.row];
self.projectName = project[#"name"];
[self callback];//You call the method when your block is finished
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
//Here you could call a different callback for error handling (or passing a success param)
}
}];
}
-(void) callback{
//Here you know the code has been executed
NSLog (#"project name = %#",self.projectName);
}

Parse -getObjectInBackgroundWithId not saving on the database

I have a code snippet that will update information in the Parse database. I set up an action so that when the information is saved, it gets updated in the background. The function is being executed, but it's not saving anything on the database. its going through the function, but no changes are being saved. The changed values are inside a text field and a switch.
- (IBAction)save:(id)sender {
NSLog(#"classnameinsave %#", self.productTitleField.text);
PFQuery *query = [PFQuery queryWithClassName:self.className];
[query getObjectInBackgroundWithId:self.productId block:^(PFObject *object, NSError *error) {
NSLog(#"inside getObjectsInBackgroundWithId function");
NSLog(#"priceinsave %#", object[#"price"]);
object[#"title"] = self.productTitleField.text;
object[#"price"] = self.priceField;
object[#"quantity"] = self.quantityField;
object[#"show"] = self.show;
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if(succeeded){
NSLog(#"Succeeded in Saving");
}else if(error){
NSLog(#"Error with saving changes %#", error);
}
}];
}];
}
Most likely this happened because the PFObject you're looking for doesn't even exist! You forgot to add the if statement for verifying if the object exists. Also, I understand you want to make it as dynamic as possible by having the class name based on a UILabel, but please don't do this, this doesn't make sense at all. Replace your code with this:
PFQuery *query = [PFQuery queryWithClassName:#"ClassName"];
[query getObjectInBackgroundWithId:self.productId block:^(PFObject *object, NSError *error) {
if(object){
//Do everything here :)
}else{
//Display an UIAlertView to the user?
NSLog(error);
}
}];
Note: You should add the if statement, however it's not necessary.
Best regards,

Resources