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 ?
Related
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];
Currently, I am querying the database twice to achieve a list of all users nearby who are not already being followed by the current user. Here is my nested query:
// List of all users being followed by the current user
PFQuery *followingActivitiesQuery = [PFQuery queryWithClassName:kFTActivityClassKey];
[followingActivitiesQuery whereKey:kFTActivityTypeKey equalTo:kFTActivityTypeFollow];
[followingActivitiesQuery whereKey:kFTActivityFromUserKey equalTo:[PFUser currentUser]];
[followingActivitiesQuery setCachePolicy:kPFCachePolicyNetworkOnly];
[followingActivitiesQuery includeKey:kFTActivityToUserKey];
[followingActivitiesQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSMutableArray *followedUserIds = [[NSMutableArray alloc] init];
// Obtain an array of object ids for all users being followed
for (PFObject *object in objects) {
PFUser *followedUser = [object objectForKey:kFTActivityToUserKey];
[followedUserIds addObject:followedUser.objectId];
}
PFGeoPoint *geoPoint = [[PFUser currentUser] objectForKey:kFTUserLocationKey];
// List of all users within 50 miles that are not already being followed
PFQuery *followUsersByLocationQuery = [PFQuery queryWithClassName:kFTUserClassKey];
[followUsersByLocationQuery whereKey:kFTUserObjectIdKey notEqualTo:[PFUser currentUser].objectId];
[followUsersByLocationQuery whereKey:kFTUserLocationKey nearGeoPoint:geoPoint withinMiles:50];
[followUsersByLocationQuery whereKeyExists:kFTUserLocationKey];
[followUsersByLocationQuery whereKey:kFTUserObjectIdKey notContainedIn:followedUserIds];
[followUsersByLocationQuery setLimit:100];
[followUsersByLocationQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.objects = objects;
[self.tableView reloadData];
}
}];
}
}];
My question is, is this a viable solution? I feel guilty about having to query the server twice in order to achieve this, but I was not able to do it all in one query. I could not compare a parse pointer from the ActivityClass to the Users class, since the Users class is the class being pointed to, and because of this I couldn't think of a way to do it all in one query.
You're in luck - this can be done in a single query using the whereKey:doesNotMatchKey:inQuery: method of PFQuery.
Parse will treat this as a single, compound query against the database. Totally guilt-free :)
Try this instead:
// List of all users being followed by the current user
PFQuery *followingActivitiesQuery = [PFQuery queryWithClassName:kFTActivityClassKey];
[followingActivitiesQuery whereKey:kFTActivityTypeKey equalTo:kFTActivityTypeFollow];
[followingActivitiesQuery whereKey:kFTActivityFromUserKey equalTo:[PFUser currentUser]];
[followingActivitiesQuery setCachePolicy:kPFCachePolicyNetworkOnly];
[followingActivitiesQuery includeKey:kFTActivityToUserKey];
PFGeoPoint *geoPoint = [[PFUser currentUser] objectForKey:kFTUserLocationKey];
// List of all users within 50 miles that are not already being followed
PFQuery *followUsersByLocationQuery = [PFQuery queryWithClassName:kFTUserClassKey];
[followUsersByLocationQuery whereKey:kFTUserObjectIdKey notEqualTo:[PFUser currentUser].objectId];
[followUsersByLocationQuery whereKey:kFTUserLocationKey nearGeoPoint:geoPoint withinMiles:50];
[followUsersByLocationQuery whereKeyExists:kFTUserLocationKey];
//The next line is your new compound query
[followUsersByLocationQuery whereKey:kFTUserObjectIdKey doesNotMatchKey:#"objectId" inQuery:followingActivitiesQuery];
[followUsersByLocationQuery setLimit:100];
[followUsersByLocationQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.objects = objects;
[self.tableView reloadData];
}
}];
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);
}];
}
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.");
}
}];
I just try to write some sample app using parse backend, i created app and test class, its worked fine for ios, for same calls if i make a PFquery call to retrive objects its crashing on mac.
PFQuery *query = [PFQuery queryWithClassName:#"stock"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (query.cachePolicy != kPFCachePolicyCacheOnly && error.code == kPFErrorCacheMiss) {
// No-op on cache miss - since the policy is not CacheOnly, this
// block will be called again upon receiving results from the network.
return;
}}];
You are setting cachePolicy wrong.
Use this:
PFQuery *query = [PFQuery queryWithClassName:#"stock"];
[query setCachePolicy:kPFCachePolicyNetworkOnly];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
}
}];