I have such construction in my code:
for (METMeetingEntity *e in self.meetingList) {
PFQuery *query = [PFUser query];
//some query constraints, depending on METMeetingEntity
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
// some query actions
NSArray *sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES]];
self.meetingList = [NSMutableArray arrayWithArray:[self.meetingList sortedArrayUsingDescriptors:sortDescriptors]];
self.meetingList = [self dateCleanup:self.meetingList];
}];
How can I perform action - reload my table view after all the findObjectsInBackground are completed
One possible solution would be to keep a count. When the number matches the original count, you know you are done.
NSUInteger count = self.meetingList.count;
for (METMeetingEntity *e in self.meetingList) {
PFQuery *query = [PFUser query];
//some query constraints, depending on METMeetingEntity
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// some query actions
NSArray *sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES]];
self.meetingList = [NSMutableArray arrayWithArray:[self.meetingList sortedArrayUsingDescriptors:sortDescriptors]];
self.meetingList = [self dateCleanup:self.meetingList];
count--;
if (count == 0) {
dispatch_async(dispatch_get_main_queue(), ^{
// reload table or whatever needs to be done
});
}
}];
}
I think you don't need calling dispatch_async. All the blocks in Parse run in the main thread. In Parse doc you can read:
Both findObjectsInBackgroundWithBlock: and
findObjectsInBackgroundWithTarget:selector: work similarly in that
they assure the network request is done without blocking, and run the
block/callback in the main thread.
This is an example of a query for a UICollectionView:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error) {
listaFiguras = [objects mutableCopy];
[_collectionView reloadData];
} else {
NSLog(#"Something wrong. No Data.");
}
}];
Related
How can I combine multiple Parse Queries?
I want to query the column sclink and songTitle from parse.com then add each to its own array.
Also how to save query locally and call it? IF else statment or something:
NSMutableArray *trackList = [[NSMutableArray alloc] init];
PFQuery *queryTracks = [PFQuery queryWithClassName:#"liveRadioPL"];
NSArray *objects = [queryTracks findObjects]; // Online PFQuery results
[PFObject pinAllInBackground:objects];
[queryTracks selectKeys:#[#"scLink"]];
[queryTracks findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
totalTracks = (int)objects.count;
NSLog(#"Successfully retrieved %lu Tracks.", (unsigned long)objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
[trackList addObject:[NSString stringWithFormat:#"%#", [object objectForKey:#"scLink"]]];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
trackListArray = trackList;
NSMutableArray *trackTitles = [[NSMutableArray alloc] init];
PFQuery *queryTitles = [PFQuery queryWithClassName:#"liveRadioPL"];
NSArray *objectsTitle = [queryTitles findObjects]; // Online PFQuery results
[PFObject pinAllInBackground:objects];
[queryTracks selectKeys:#[#"songTitle"]];
[queryTracks findObjectsInBackgroundWithBlock:^(NSArray *objectsTitle, NSError *error) {
if (!error) {
// The find succeeded.
totalTitles = (int)objectsTitle.count;
NSLog(#"Successfully retrieved %lu Titles.", (unsigned long)objectsTitle.count);
// Do something with the found objects
for (PFObject *object in objects) {
[trackTitles addObject:[NSString stringWithFormat:#"%#", [object objectForKey:#"songTitle"]]];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
I'm not sure your logic really makes sense - you're using 4 API requests when all you need is 1 API request. Also, Jacob is right, you're filling an array from a background thread and as a result the main thread will see it as empty.
I think I understand what you're trying to do - try this
PFQuery *queryTracks = [PFQuery queryWithClassName:#"liveRadioPL"];
// use includeKey if slink and songTitle are pointers to other Parse classes
// from the context of your question you probably don't need to use includeKey
[queryTracks includeKey:"scLink"];
[queryTracks includeKey:"songTitle"];
NSArray *objects = [queryTracks findObjects];
NSMutableArray* scLinks = [[NSMutableArray alloc] init];
NSMutableArray* songTitles = [[NSMutableArray alloc] init];
for (PFObject* object in objects) {
[scLinks addObject:object[#"scLink"]];
[songTitles addObject:object[#"songTitles"]];
}
I hope this helps, good luck!
I am trying to return users from my User class with a UISearchBar and UITableView. For some reason I can't retrieve any objects from the User class in Parse. Do you have any idea why I can't get any objects, even if there are a lot of users in the User class?
Here's how I'm doing it:
- (void)refresh {
PFQuery *query = [PFQuery queryWithClassName:#"User"];
[query orderByAscending:#"createdAt"];
query.limit = 1000;
[query findObjectsInBackgroundWithBlock:^(NSArray *posts, NSError *error) {
if (!error) {
[_refreshControl endRefreshing];
[_people setArray:posts];
[_tableView reloadData];
NSLog(#"%#", posts);
} else {
NSLog(#"Error fetching users");
}
}];
}
Try replacing the first line in your method with:
PFQuery *query = [PFUser query]
I'm trying to call below parse retrieving method in another dispatch block but it never calls. I'm suspect calling a block in another block doesn't allowed but not sure. Does anybody have any idea about why findObjectsInBackgroundWithBlock isn't called?
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
PFQuery *query = [PFQuery queryWithClassName:#"quotes"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSMutableArray *tempQuotes = [[NSMutableArray alloc] init];
for (PFObject *object in objects) {
[tempQuotes addObject:[object objectForKey:#"quote"]];
}
quotes = tempQuotes;
}
}];
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate postRefreshing];
});
});
I changed my inner parse query as below (without any background block) and it worked. I should know that you can't call a method in background if you are already in a dispatch block.
PFQuery *query = [PFQuery queryWithClassName:#"quotes"];
NSArray* quotesArray = [query findObjects];
i am newbie here in iOS and Parse Framework i want to fetch data from my Parse table from PFQuery like as
NSUInteger limit = 1500;
PFQuery *query = [PFQuery queryWithClassName:#"MapInfo"];
[query setLimit: limit];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (!error) {
NSLog(#"Successfully retrieved: %#", objects);
} else {
NSString *errorString = [[error userInfo] objectForKey:#"error"];
NSLog(#"Error: %#", errorString);
}
}];
it is Working as i want but it is give me only 1000 objects i want here to fetch all my table data it contain unto 2000 object and it will increment as day by day please help me for this.
For this Now i write a code like this but it is Only Give me 1000 Objects only
NSMutableArray *allObjects = [NSMutableArray array];
NSUInteger limit = 0;
__block NSUInteger skip = 0;
PFQuery *query = [PFQuery queryWithClassName:#"MapInfo"];
[query setLimit: limit];
[query setSkip: skip];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
[allObjects addObjectsFromArray:objects];
if (objects.count == limit) {
skip += limit;
[query setSkip: skip];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(#"Array %#",objects);
}];
}
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
thanks.
I believe there is a query limit on the number of objects that can be fetched. What I would do is query make two queries for the same thing but for the second query, do something like this
[query setSkip1000];
you can skip the first 1000 objects in the first query and grab the next 1000. Make your array an NSMutableArray and inside each block do this
[self.myArray addObjects:objects]; instead of self.myArray = objects; that way you are overwriting the objects in your array.
Edit
Instead of 2 separate queries you can also do this
NSMutableArray *allObjectsArray = [NSMutableArray array];
//Set this to the amount of objects you want. Has to be be 1000 or less
NSUInteger limit = 0;
//Set this to the amount you want to skip (Usually 0)
NSUInteger skip = 0;
PFQuery *query = [PFQuery queryWithClassName:#"tempClass"];
[query setLimit: limit];
[query setSkip: skip];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded. Add the returned objects to allObjects
[allObjectsArray addObjectsFromArray:objects];
if (objects.count == limit) {
// There could be more objects in your database. Update the skip number and perform the same query.
skip = skip + limit;
[query setSkip: skip];
[query findObject...// Exactly the same way as you did before to get the rest of your objects in the database
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
This is a simple recursive solution to retrieve all the objects from a class using blocks.
Here is how you initially call it.
[self queryAllObjectswithLimit:1000 withSkip:0 withObjects:#[] withSuccess:^(NSArray * objects) {
//All the objects
} failure:^(NSError * error) {
//
}];
Here is the method.
- (void)queryAllObjectswithLimit:(NSUInteger )limit withSkip:(NSUInteger )skip withObjects:(NSArray *)objects withSuccess:(void (^)(NSArray *objects))success failure:(void (^)(NSError *error))failure {
//Store all the Objects through each layer of recurrsion
NSMutableArray *allObjects = [NSMutableArray arrayWithArray:objects];
PFQuery *query = [PFQuery queryWithClassName:#"Class_Name"];
query.limit = limit;
query.skip = skip;
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
if (!error) {
// The find succeeded. Add the returned objects to allObjects
[allObjects addObjectsFromArray:objects];
if (objects.count == limit) {
//Recursively Call this until count does not equal limit, then begin returning all the objects back up
[self queryAllObjectswithLimit:limit withSkip:skip+limit withObjects:allObjects withSuccess:^(NSArray * objects) {
//This will return everything
success(objects);
} failure:^(NSError * error) {
failure(error);
}];
} else {
success(allObjects);
}
} else {
failure(error);
}
}];
}
I've tested this with less than 1000 objects, 1000 objects, and more than 1000 objects and it works perfectly.
Be cautious of how many objects you're grabbing though because this will grab all of them and if you're working with a large data set that might be an issue in terms of memory very quickly.
https://parse.com/questions/fetch-all-data-in-a-table-using-pfquery
You can use the skip and limit parameter to paginate through all objects in the table by adding the value of limit to skip until the query returns an amount of objects that is less than limit.
NSMutableArray *allObjects = [NSMutableArray array];
NSUInteger limit = 0;
__block NSUInteger skip = 0;
PFQuery *query = [PFQuery queryWithClassName:#"MapInfo"];
[query setLimit: limit];
[query setSkip: skip];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded. Add the returned objects to allObjects
[allObjects addObjectsFromArray:objects];
if (objects.count == limit) {
// There might be more objects in the table. Update the skip value and execute the query again.
skip += limit;
[query setSkip: skip];
[query findObjects... // Execute the query until all objects have been returned. Keep adding the results to the allObjects mutable array.
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
This is basically killing my app and Parse isn't exactly being prompt with their responses.
Queries on pointer arrays aint working.
Try this in your app:
- (void)runTest{
// Run a build to store 20 rows.
for(int i=0;i<20;i++){
NSMutableArray *recipients = [NSMutableArray array];
[recipients addObject:[PFUser currentUser]];
PFObject *message = [PFObject objectWithClassName:#"Run"];
[message addObjectsFromArray:recipients forKey:#"recipients"];
[message saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
}];
}
}
- (void)runTestQuery{
// Run a second build to query the 20 rows. Not all 20 are returned.
PFQuery *query = [PFQuery queryWithClassName:#"Run"];
[query whereKey:#"recipients" equalTo:[PFUser currentUser]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(#"Objects count: %li",(long)objects.count);
}];
}