I am trying to use local-datastore with iOS.
Say I have two or more devices.
I use saveEventually to save data locally (and on cloud). When working only on one device it works fine.
When I start working with more than one device, to sync I use:
PFQuery *query = [UserPreference query];
[query whereKey:#"userId" equalTo: [PFUser currentUser].objectId];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error){
if(!error){
[UserPreference pinAllInBackground:objects block:^(BOOL succeeded, NSError *error) {<---- objects here are fine
if(succeeded){
[query fromLocalDatastore];
NSLog(#"Local %#", [(UserPreference*)[[query findObjects] objectAtIndex:0] filterContext ]); <--- however here the old value is retrieved
}
}];
}
}];
So I get proper objects from the cloud, then i PinAll but when i retrieve from localDataStore Old values are retrieved?
Could anyone be kind to explain :
1. if this is feasible at all i.e to sync between two devices using local data store
2. what I am doing wrong?
PS: I notice that serverData in objects contains the correct info but does not update the object
It seems that this works. So when you get update from server you need to unpin all objects with name, and then pin them back with the same name. After that you can query pinWithName:
PFQuery *query = [UserPreference query];
[query whereKey:#"userId" equalTo: [PFUser currentUser].objectId];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error){
[UserPreference unpinAllObjectsInBackgroundWithName:#"userPreference" block:^(BOOL succeeded, NSError *error) {
[UserPreference pinAllInBackground:objects withName:#"userPreference"];
}];
}
I have the same requirement, I've found the above helpful, but have some further data and a different option that others may find useful.
I also have two devices. All data is in the local datastore and pushed up to parse server, this works well and I can see the data on the server. However, when I log into a second fresh device with the same account details I do not get all the data.
After logging in with :
[PFUser logInWithUsernameInBackground:user password:pass block:^(PFUser *user, NSError *error) {
if (user) { /* success, user object is in local datastore */ }
}];
If successful, any data associated with the user object is available. But any other objects related to this user have to be requested. Hence, fields accessed through the user object are there, but records related to the user object are not. I found the following to work to get the additional data:
PFQuery *query = [PFQuery queryWithClassName:#"History"];
[query whereKey:#"user" equalTo:[PFUser currentUser]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error){
NSLog(#"Fetched %lu objects", (unsigned long)[objects count]);
for (PFObject* item in objects)
[item pinInBackground];
} else {
NSLog(#"Parse error pulling data after login: %# %#", error, [error userInfo]);
}
}];
Finally, if you expect the data on the server to change, you do have to poll for it. I have updated the data on the server through the parse login on the web and I, at least, do not see these changes propagate to the device. I have to pull them down with a query and then pin them.
Related
I have a little problem with loading and sending data to parse.com.
I want to read an Array from parse User Class, adding it and send it back to parse.com.
The following code shows how it would work for a "normal" Class to send an array:
PFQuery *query = [PFQuery queryWithClassName:#"myOwnClass"];
[query getObjectInBackgroundWithId:#"myObjectID"
block:^(PFObject *gameScore, NSError *error) {
[gameScore addUniqueObjectsFromArray:#[#"Name1", #"Name1"] forKey:#"Friends"];
[gameScore saveInBackground]; }];
To Get The Array...Change your PFQuery Method:
-(void)FetchFromPFUserClass{
PFQuery*query = [PFUser query];
[query getObjectInBackgroundWithId:#"myObjectID"
block:^(PFObject *gameScore, NSError *error) {
if(error==nil){
[gameScore addUniqueObjectsFromArray:#[#"Name1", #"Name1"] forKey:#"Friends"];
[gameScore saveInBackground];
}
}];
}
I have a Filter class which has a pointer to a user in my User class. I'm wondering how can I get the Filter object in the Filter class which is equal to the [PFUser CurrentUser] and then get both column values from the User and Filter class
PFQuery *filterQuery = [PFQuery queryWithClassName:#"Filter"];
filterQuery.limit = 1;
[filterQuery whereKey:#"userId" equalTo:[PFUser currentUser].objectId];
[filterQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error){
NSLog(#"%#", objects);
}
}];
You just use the object itself...
PFQuery *filterQuery = [PFQuery queryWithClassName:#"Filter"];
filterQuery.limit = 1;
[filterQuery whereKey:#"userId" equalTo:[PFUser currentUser]]; //no need to put objected here.
[filterQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error){
NSLog(#"%#", objects);
}
}];
As long as the userId field is a pointer to the _User object then this will work.
If userId is a pointer to _User then you can add...
[filterQuery includeKey:#"userId"];
This will then populate the userId object of the Filter objects with data when they are sent down. If you don't put that line then you will just get the objectId in the userId object.
However, I'm not sure you've done it as a Pointer. Can you confirm that it definitely is.
You should have this in the Data Browser table for Filter...
(follower will say userId on yours)
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) {
}
}];
In my "Message" table in Parse I have a field called conversation, which is a pointer to a Conversation (another table in my database).
To query for a Message, can I do:
PFQuery *messageQuery = [PFQuery queryWithClassName:#"Message"];
[messageQuery whereKey:#"conversation" equalTo:_conversation.objectid];
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
...
}];
or do I have to get the actual PFObject *myConversation and use that...
PFQuery *messageQuery = [PFQuery queryWithClassName:#"Message"];
[messageQuery whereKey:#"conversation" equalTo:myConversation];
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
...
}];
It seems that #1 doesn't work, but #2 does...my question is how can I get #1 to work (i.e. use a PFObject's id to query when I have a pointer field)
.objectId is just a string, if your "conversation" key contains a pointer to myConversation, then you must include a PFObject in the equal to.
If you only have the objectId, you can search pointers without data using:
PFObject * myConversation = [PFObject objectWithoutDataWithClassName:#"Conversation" objectId:_conversation.objectid];
// continue here
[messageQuery whereKey:#"conversation" equalTo:myConversation];
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
...
}];
I'm trying to query a PFRelation of the current user of the app to load a table view showing all of the users friends. Each user is saved under a class called "User" when they first use the app and once they add a friend that friend is added to the column "friendsRelation" for the user. I'm using this code i got got from this link and nothing is returned from the query.
PFQuery *query = [PFQuery queryWithClassName:#"User"];
[query whereKey:#"friendsRelation" equalTo:[PFUser currentUser]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"An error occurred fetching friends");
}
else {
[self.friends addObjectsFromArray:objects];
[self.tableView reloadData];
}
}];
Try this:
PFRelation *relation = [[PFUser currentUser] relationForKey:#"friendsRelation"];
PFQuery *query = [relation query];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
// results contains all friends of current user
}];
You are not query the PFUser table, so you cannot use [query whereKey:#"friendsRelation" equalTo:[PFUser currentUser]]; to query the User table, since the friendsRelation does not contain any PFUser objects but User objects. Just get the User object which represent for current user and use it to query the relation.
To Query the Users table don't use
[PFQuery queryWithClassName:#"User"];
Use instead
[PFUser query];
Only use the first if you have created your own "User" table and at this point if you checked the Data-browser you will see two different tables both called "User".