I am testing out Parse localDatastore and am struggling with refreshing the local datastore after a new server PFQuery.
The PFQuery works fine and seems to pin the array to the local datastore just fine. When I change the contents of the array on the server, the server PFQuery pulls down the updated array, but the local datastore doesn't seem to update:
- (void)viewDidLoad {
[super viewDidLoad];
// Query Parse
PFQuery *query = [PFQuery queryWithClassName:#"contacts"];
NSArray *objects = [query findObjects];
[PFObject pinAllInBackground:objects block:^(BOOL succeeded, NSError *error) {
if(succeeded) {
NSLog(#"Successfully retrieved %lu records from Parse.", (unsigned long)objects.count);
} else if (error) {
NSLog(#"Error");
}
}];
}
and then a UIButton is used to log the contents of the local datastore to the console:
-(IBAction)showDatastore {
// Query the Local Datastore
PFQuery *query = [PFQuery queryWithClassName:#"contacts"];
[query fromLocalDatastore];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSLog(#"Successfully retrieved %lu contacts from Datastore.", (unsigned long)objects.count);
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
In my sample the original array has 15 objects. Both the count's from each array initially are 15. I then remove an object from the server array and the initial PFQuery count is 14, but the local datastore count remains 15.
Parse's documentation states:
When an object is pinned, every time you update it by fetching or saving new data, the copy in the local datastore will be updated automatically.
But that doesn't seem to be the case... at least not with this recommended code. Is there something i'm missing?
It depends on how you are deleting the object. If you're using deleteEventually, then the deletion will propagate to the LDS
You can query from the local datastore using exactly the same kinds of queries you use over the network. The results will include every object that matches the query that's been pinned to your device. The query even takes into account any changes you've made to the object that haven't yet been saved to the cloud. For example, if you call deleteEventually, on an object, it will no longer be returned from these queries.
But any other method requires explicit unpinning if you want it to work.
deleteEventually is the prefered method I believe.
Related
I am using below code to fetch users but I am not able to get it.. app is crashes... Please help me to get all installation objects list..
PFQuery *userQuery = [PFQuery queryWithClassName:#"_Installation"];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
NSLog(#"objc...%#",objects);
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"id...%#",object.objectId);
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
Try this:
PFQuery *userQuery = [PFInstallation query];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
NSLog(#"objc...%#",objects);
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"id...%#",object.objectId);
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
FYI, Wain is correct in his comment that installations are not users. Are you sure this is the class you want to query?
With Parse, as flexible and sound it is, they are limitations to it. Some are extremely worrying in my opinion as a developer that uses Parse, and some are just implemented server side to protect your end-users. This is one, you can not query the Installation class from a client, the only columns you can query are listed in the API Reference . However, you can query the class through a cloud function using the master key, otherwise, you will have to use a pointer/relation to other tables for whatever data you want to retrieve. Additionally, for future question seekers, please refer to Wains note. It's a valid statement and should be considered prior to proceeding with anything. Users are not installations, the same 'user' i.e., device, can re-download the app multiple times creating numerous installations (not users).
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 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 have several Classes one of which one is User and another one is TestObject. If I query User (which I learned by trial & error that it should queried as _User) I get the correct record count, but if I query TestObject I get 0. This happens for some Classes but not for all. Why is that?
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
} else {
NSLog(#"Successfully retrieved %d scores.",objects.count);
}
}];
This returns:
2012-10-19 13:55:03.239
TableViewParseDotCom[5497:10103]
Successfully retrieved 24 scores.
But if I change the line, to:
PFQuery *query = [PFQuery
queryWithClassName:#"TestObject"];
I get 0 count, but I know I have 45 records. Why?
The most common reason for this is you've queried for objects which you don't have access to. Double check that if these objects have an ACL you are logged in as the same user.
Along with checking the ACL's for the objects you're querying, you should also take a look at the Settings in the Parse dashboard. If you don't want to force users to log in ensure that "Allow Anonymous Users" is set on On.
Also, in the data browser for the TestObject object, click on the "More" button and then select "Permissions" from the dropdown. Ensure your settings are correct for "Find" and "Get" - set to public with no roles/users to start with to help your debugging. That should ensure that you can query your TestObject objects.
Don't forget to set the read permissions. These can be programatically set as below:
PFACL * defaultACL = [PFACL ACL];
[defaultACL setPublicReadAccess:YES];
[PFACL setDefaultACL:defaultACL withAccessForCurrentUser:YES];
I just ran two queries, one on my users and one on another class (imageClass) and they both returned fine.
User query:
// Remember for users we can run a user query instead of needing to specify the class
PFQuery * userQuery = [PFUser query];
[userQuery whereKey:#"username" equalTo:currentUser.username];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray * objects, NSError *error) {
}];
Other class query:
PFQuery * imageQuery = [PFQuery queryWithClassName:#"bImageClass"];
[imageQuery findObjectsInBackgroundWithBlock:^(NSArray * objects, NSError *error) {
}];
Here is a picture of my classes in Parse.
So I would make sure you have the public access set correctly (in my project this is set just before a query runs) as the code you are using for the queries looks fine.