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];
Related
At a time in my app, the user have a timeline where are displayed posts from their friends, but randomly, the queries are stopped and not executed anymore,
more exactly, I had a problem before that: my app was frozen at psynch_mutexwait, I fixed it by using: dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ }); for queries that runs on background thread, but more precisely:
I have 2 queries that runs in loop every 3 and 4 seconds respectively, made by 2 respective shcheduled NSTimer
the first query loop for new posts (in this case the user do not have to refresh manually):
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
PFQuery *query = [PFQuery queryWithClassName:#"Posts"];
[query whereKey:#"user" notEqualTo:[PFUser currentUser]];
[query whereKey:#"user" containedIn:self.allFriends];
[qFriendInfo findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
//Used to display results in UICollectionView
self.AllPosts = [[NSArray alloc] initWithArray:objects];
}
});
the second query is querying users's state, for example if a user is "online", "offline", or "disconnected"
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
PFQuery *query = [PFUser query];
[query whereKey:#"objectId" notEqualTo:[PFUser currentUser].objectId];
[query whereKey:#"objectId" containedIn:self.allFriendsIds];
[qFriendInfo findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
//Used to display results in UICollectionView
self.allUsers = [[NSArray alloc] initWithArray:objects];
}
});
All works properly by using dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ });
but randomly, the queries are stopped (the app is not frozen either...) (I can see this by NSLog in the console) and when I pause, in the left window I can see the background thread on semaphore_wait_trap
does anyone have an idea for how to fix that issue ?
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 have a NSOperation that gets an array of message objects and cycles through them. For each message object I want to add a UIView to the current UIViewController. Only problem is I can't access the view from the NSOperation. Is there any way around this?
Thanks
code below (my main method in the NSOperation):
- (void)main {
//main code here
NSLog(#"Display messages");
//First match the user with the messageBank
PFQuery *messageBankQuery = [PFQuery queryWithClassName:#"messageBank"];
[messageBankQuery whereKey:#"username" equalTo:[PFUser currentUser].username];
[messageBankQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error) {
//first object matches
PFObject *messageBank = objects[0];
PFRelation *receivedMessages = [messageBank relationForKey:#"receivedMessages”];
PFQuery *receivedMessagesQuery = [receivedMessages query];
[receivedMessagesQuery orderByAscending:#"createdAt"];
[receivedMessagesQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if((!error) &&([objects count]>0)) {
for(PFObject *message in objects) {
UIView *content = [[[NSBundle mainBundle] loadNibNamed:#"messageView" owner:self options:nil] objectAtIndex:0];
//this doesn't have a view to add to!!!
}
[self completeOperation];
}//end if
else {
[self completeOperation]; }
}];
}
}];
}
I would like to create a simple method in one of my helper class that returns an NSString, but I can't figure out the right way to return the value. I get this error inside the if statement.
Variable is not assignable (missing __block type specifier)
+ (NSString *) photoCount {
NSString *numberOfPhoto = [[NSString alloc] init];
PFQuery *photoQuery = [PFQuery queryWithClassName:#"PhotoContent"];
[photoQuery whereKey:#"usr" equalTo:[PFUser currentUser]];
[photoQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (objects) {
numberOfPhoto = [NSString stringWithFormat:#"%d", [objects count]];
}
}];
return numberOfPhoto;
}
What did I wrong? I've tried to return the string directly from the block, but it doesn't helped.
You are calling asynchronous method, so you cannot return the value immediately, but rather you want to adopt the asynchronous completion block pattern:
+ (void) photoCountWithCompletionHandler:(void (^)(NSInteger count, NSError *error))completionHandler {
NSParameterAssert(completionHandler);
PFQuery *photoQuery = [PFQuery queryWithClassName:#"PhotoContent"];
[photoQuery whereKey:#"usr" equalTo:[PFUser currentUser]];
[photoQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (objects) {
completionHandler([objects count], nil);
} else {
completionHandler(-1, error);
}
}];
}
And then when you call it, it would be something like:
[MyClass photoCountWithCompletionHandler:^(NSInteger count, NSError *error) {
if (error) {
// handle the error here
NSLog(#"photoCountWithCompletionHandler error: %#", error);
self.textLabel.text = #"?";
} else {
// use `count` here
self.textLabel.text = [NSString stringWithFormat:#"%ld", (long) count];
}
}];
// do not use `count` here, as the above block is called later, asynchronously
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.");
}
}];