I dont know what the deal with parse is but for some reason it wont allow me to save the retrieved array into a mutable array I created. It works inside the parse code block but once outside, it displays null. Help please?
PFQuery *query = [PFQuery queryWithClassName:#"comments"];
[query whereKey:#"flirtID" equalTo:recipe.flirtID];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
comments = [[NSMutableArray alloc]initWithArray:objects];
// Do something with the found objects
for (PFObject *object in objects) {
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
NSLog(#"%#",[comments objectAtIndex:0]);
It's actually working as it should.
You should read up on how blocks work.
Edit: Try reading Apple's Documentation
You're NSLogging 'comments' before comments actually gets set. How does that work?
You see, query is running in the background, and it will actually take a bit of time. It's running asynchronously. But the code outside the block will run immediately.
While the code comes before, because it's an asynchronous block, it can and will be run whenever.
Try this:
comments = [[NSMutableArray alloc]initWithArray:objects];
NSLog(#"%#",[comments objectAtIndex:0]);
The important question is, what do you want to do after the query? Looks like you want to save comments, but then what? That will determine what you do next.
Related
I have a view controller with inside table and I want to fill her with an array saved on Parse. To download the data I use this code:
PFQuery *query = [PFQuery queryWithClassName:#"myClass"];
[query whereKey:#"X" equalTo:#"Y"];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if(error==nil){
myArray=[object objectForKey:#"Z"];
NSLog(#"%#",myArray);
}
}];
}
Now I display it inside myarray the data on parse. But if I use arrays to populate the table it is always me empty. I used NSLog and I saw that outside of the method [query getFirstObjectInBackgroundWithBlock: ^ (PFObject * object, NSError * error) my array is always empty.
How can help me?
Fetching data from a remote database takes a little time. The parse functions that take block params run asynchronously. See the comments within your slightly modified code...
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if(error==nil){
// this appears first in the file, but runs later
// after the request is finished
myArray=[object objectForKey:#"Z"];
NSLog(#"%#",myArray);
// tell our view that data is ready
[self.tableView reloadData];
}
}];
// this appears second in the file, but runs right away, right
// when the request is started
// while execution is here, the request isn't done yet
// we would expect myArray to be uninitialized
Be sure, in your datasource methods e.g. numberOfRows to answer myArray.count. And use the data in the array myArray[indexPath.row] when building the table view cell.
I am new with Parse and Ios-development.
I develop a ios-app that use Parse as backend.
I have got the main-function to work now, but i have a BIG problem.
I want to create a separate class for my API-handling to Parse. As i set it up now i have my parse-code directly in my view-controllers and as far as i know that not that nice coding.
But, the issue is to handle the background-jobs. Let say if i want to do a GET from the server, this can be done in a background-thread, just using "findObjectsInBackgroundWithBlock"
The problem is when i move this method to a separate API-class. Then my ViewController ask my API-class to get all the objects an the API-class will return it as soon its done. It will nor run in the background, i cant return a NSMutableArray with objects to the viewController until the fetch is done.
I have thinking that i maybe can get the data from parse synchronously in my API-class by using [query findObjects:&error] , as long as i figure out how to create my get-method in the API-class to run asynchronously.
I have try to create my API-method as a asynchronously method using blocks but will not run in background on a separate thread. (I am new to blocks an dont evan no if thats the correct way to crate a method that will run in a separate thread when using it)
Here is my API-method (Class: APIClient)
+ (void) GETAllShoppingGroups:(void (^) (NSMutableArray*))completionBlock{
//Create a mutable array (nil)
NSMutableArray *shoppingGroupsArray = nil;
//Create query for class ShoppingGroupe
PFQuery *query = [ShoppingGroupe query];
//Filter - find only the groups the current user is related to
[query whereKey:#"members" equalTo:[PFUser currentUser]];
//Sort Decending
[query orderByDescending:#"createdAt"];
//Tell Parse to also send the real member-objects and not only id
[query includeKey:#"members"];
//Send request of query to Parse with a "error-pointer"and fetch in a temp-array
NSError *error = nil;
NSArray *tempArray = [NSArray arrayWithArray:[query findObjects:&error]];
//Check for success
if (!tempArray) {
NSLog(#"%#", error);
NSLog(#"ERROR: %#", [error userInfo][#"error"]);
return completionBlock(shoppingGroupsArray);
} else {
//Seccess
shoppingGroupsArray = tempArray.mutableCopy;
completionBlock(shoppingGroupsArray);
}
}
Here is my ViewController Class (Class: ShoppingGruopViewController)
- (void) getAllObjects{
//Init array if nil
if (!self.shoppingGroupeArray) {
self.shoppingGroupeArray = [[NSMutableArray alloc]init];
}
//Remove old objects
[self.shoppingGroupeArray removeAllObjects];
//Get objects
[APIClient GETAllShoppingGroups:^(NSMutableArray* completionBlock){
if (completionBlock) {
[self.shoppingGroupeArray addObjectsFromArray:completionBlock]; }
[self.tableView reloadData];
}];
}
I am running the query detailed below. It does not log any error and proceeds to log the objects array. When it logs the objects array it displays every object within it up until the first object that was added to the class today. No objects other than the first one added today are displayed. If I delete the first object from today it will display every object up until the new first object for today.
PFQuery *query = [PFQuery queryWithClassName:#"className"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSLog(#"%#", objects);
}
} else {
NSLog(#"Error: %#", error);
}
}];
I wasn't able to figure out why this was occurring so I simply created a new class and added all of the values from my old class to it and it began to work.
I have an array in the Data Browser that is supposed to have a list of users who've received an item from a user. The actual content of the tile is
[{"__type":"Pointer","className":"_User","objectId":"3zQoMVRJOx"}]
I can't figure out how to actually call,use, and display this data from Xcode.
My end goal is to be able to find the total number of users who've been sent an item so this is why I need the content from the array. Any help would be great. Im sure it is probably a simple line of code that I'm not seeing.
Your question actually qualifies for a "too broad" flag, as it seems you haven't tried this yourself and are experiencing problems, but are asking us to supply the code for you. It is not just a simple line of code.
However, I will supply you with code snipped from the ios guide over at Parse, slightly altered to get the array you're after:
PFQuery *query = [PFQuery queryWithClassName:#"GameScore"];
[query whereKey:#"playerName" equalTo:#"Dan Stemkoski"];
[query includeKey:#"receivers"]; // Force parse to include the user objects of receivers
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
// Write to log the email of every receiver
for (PFUser *receiver in object[#"receivers"]) {
[receiver fetchIfNeeded]; // fetches the object if it is still just a pointer (just a safety; it should be already included by the includeKey call earlier in the code
NSLog(#"Receiver: %#", receiver[#"email"]);
}
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
Good luck :-)
I want to save PFObjects from a Parse query in an NSMutableArray that my class has called listdata. I will later use the listdata array. When I traced through my code, it updated the highScoreObjects array for each object found. But when I try to set the listdata array to the highScoreObjects array, the highScoreObjects array is empty. Is there a way to keep the data after the query ends?
NSMutableArray *highScoreObjects = [[NSMutableArray alloc] initWithCapacity:5];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
[highScoreObjects addObject:object];
NSLog(#"%#", object.objectId);
}
dispatch_async(dispatch_get_main_queue(), ^ {
[self.tableView reloadData];
});
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
self.listData = highScoreObjects;
I also tried keeping the line self.listData = highScoreObjects;
inside the self.listData = highScoreObjects; loop. This didn't make any difference.
It isn't that it isn't set. It's that it isn't set yet. This is because you're using findObjectsInBackgroundWithBlock and the asynchronous process hasn't completed yet.
Move your assignment (self.listData = highScoreObjects;) into the block, just before you dispatch the request to reload the table view.
This is yet another case of not understanding the nature of asynchronous programming.
Consider this situation:
You want to make an egg sandwich. You put the eggs on to boil, and set an alarm for when they're cooked to get them out, peel them, cut them up and add them to your sandwich. While you wait you get the bread and butter it, then wait for the alarm to go off.
Your call to findObjectsInBackgroundWithBlock is putting the eggs on to boil. The block you pass it is the alarm and what you plan to do with the eggs once cooked.
Your code above is akin to putting the eggs on to boil, then straight away trying to use the uncooked/partially-cooked eggs on your sandwich. Makes a big mess.
The solution is to call a method at the end of the block your pass to the method.