Parse doesn't return PFObject - ios

I have a pointer to an object in my [PFUser currentUser] and when I'm trying to access values inside that object I get internal ObjC exception breakpoint.
this is my code:
PFObject *object = [PFUser currentUser][#"localityData"];
NSString *value = [object objectForKey:#"language"];
I get the error on the second line.
Also, Unless I do
[[PFUser currentUser] fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) { ...
every time I ask for
[[PFUser currentUser] objectWithKey:#"SOMEKEY"]
I get nil in return, why is this happening?

Parse doesn't fetch for you automatically, except a few pieces of data in specific scenarios. Like, when a user logs in the current user will be fetched and will include the standard user data - but it won't include any custom data.
If you fetch an object then that objects details will be downloaded, but the details of related objects won't - unless you specifically request it to be included in the query that you make (using includeKey:).
It's generally best to always use fetchIfNeededInBackgroundWithBlock: if you aren't sure whether the data you need has been obtained yet. Not doing this shouldn't cause a crash but it will generally cause you issues with missing information. It's possible that the crash is related to parse using exceptions for navigation in the framework, but that's a guess and you might want to try contacting parse to see if you can get more details.

Related

Parse.com caching with localDataStore enabled

I have caching problems in the iOS-Parse-SDK and I don't know what is wrong. I'm using the local datastore and it runs smoothly. But sometimes when I call a PFCloud function I don't get the current but an old version of an object or at least some fields of it are old (in my case it is a custom object with the field "status"). The strange thing is if I call the same function in the dev console on the Parse site I get the updated object. Is there anything I can do to prevent caching within the app or at least make sure I get the current version of an object?
Example PFCloud call:
[PFCloud callFunctionInBackground:#"importFriends"
withParameters:#{#"phoneNumbers": numbers}
block:^(NSDictionary *result, NSError *error) {
if (!error) {
DDLogDebug(#"Request Send Numbers SUCCESS: %#", result); //result objects are out of date
if (successBlock) successBlock(result);
}else{
DDLogDebug(#"Request Send Numbers FAIL: %#", error);
if (failedBlock) failedBlock(error);
}
}];
It seem like when you use the localdatastore and custom classes for any object you can't overwrite it's setters otherwise parse will never change it again. Even though the setter did exactly what a normal setter would do just a little bit more math afterwards.

How to find all classes on parse core database?

I have multiple classes on my app project on parse and I was wondering if there is a way where I can get ALL the class names with a query on objective-c?
Below is the code I have.
PFQuery *query = [PFQuery queryWithClassName:#"ClassNameID"];
[query getObjectInBackgroundWithId:#"key" block:^(PFObject *key, NSError *error) {
//code goes here
}];
ClassNameID is the classname on my parse database, but I want the user to select its own database that I have on parse, how do I get all the classnames?
You have to use REST Schema API to get all of your Class details in your app instead of a query.
From Parse blog: http://blog.parse.com/announcements/releasing-the-schema-api/
Documentation: https://www.parse.com/docs/rest/guide#schemas

Parse unpinFromBackground doesn't work

I'm currently using Parse to save details about users in an app. When the ViewController is loaded for the first time, the user data is retrieved from the server. When the user leaves the ViewController, I use the code [user pinInBackground] to save user variables to the local datastore. When the ViewController is reloaded later, the user variables are set using the data from the local datastore. This works correctly in my app.
However, when the user leaves to a specific view controller, on returning to the original ViewController, I wish for the app to access the data from the server instead of the local datastore. To do this, I use the code:
[user fetchFromLocalDatastoreInBackgroundWithBlock:^(PFObject *object, NSError *error) {
[user unpinInBackgroundWithName:#"MAINPIN" block:^(BOOL succeeded, NSError *error) {
[user fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) {
NSLog([NSString stringWithFormat:#"personalHeaderString is equal to %#", user[pfPersonalHeader]]);
}];
}];
}];
The NSLog shows that the code is definitely run as intended. However, the NSLog also shows that the data is not unpinned, and instead the app continues to use data from the local datastore, rather than fetching the data from the Parse server as fetch is supposed to do. How can I fix this?
All help appreciated.
Is there a reason that you are fetching from the local datastore before you unpin? I'm guessing that when you pin the result initially you give it the name "MAINPIN" so why not use:
PFObject.unpinInBackgroundWithName:("MAINPIN")
and then run a your "live" query after after this?
More info here: https://parse.com/docs/ios/api/Classes/PFObject.html#//api/name/unpinInBackgroundWithName:
Andrew

How to update an object in Parse

So I am trying to create an iOS wait time app for an amusement park that utilizes parse.com to sync data across all instances of the app. What I want to happen is when an IBAction is run, an object will update with the new wait time. Here is the code I have in that IB Action.
PFQuery *query = [PFQuery queryWithClassName:#"GrandCarousel"];
[query getObjectInBackgroundWithId:#"9Fo5FBABpL" block:^(PFObject *updatedWaitTime, NSError *error) {
updatedWaitTime[#"waitTime"] = localGrandCarouselWaitTime;
[updatedWaitTime saveInBackground];
}];}
Thats the only code in that method. Whenever I run the method, the app crashes why?! Here is a picture of that class in the parse data browser: http://s8.postimg.org/y9ti6dzxx/Screen_Shot_2014_07_12_at_6_20_22_PM.png
(It won't let me add a picture directly yet) As you can see, I am very new to parse and pretty new to objective C. Any help would be awesome!

Can parse cache replace core data

I'm building a simple contact directory with CRUD functions, and I want to have editing functionality offline. My database for the contacts will be stored on a Parse.com backend. Would this be possible using the Parse cache functionality, or would it be better for me to resort to using Core Data?
No, it can't. Parse simply caches the results of your queries. This is extremely limiting and not the same as caching all of your PFObjects. For example, say you ran a query for all of your "contacts" PFObjects. The only thing you would be able to do with the cache is run the exact same query again later (and get the exact same result). You couldn't even query for a subset of that cached data.
Another issue is the cached objects will not be updated with any changes your user is making to your PFObjects. For example, say a user is editing contacts offline and your code is calling saveEventually to save those changes to Parse when possible. When you get a cached query result the user's changes will not be reflected in your PFObjects. The same goes for deleted and added PFObjects I believe. This would make offline use terrible. Here is a thread from the Parse forum that touches on this subject:
https://www.parse.com/questions/does-saving-an-object-supposed-to-update-the-local-cache-of-a-query-on-these-objects
I have seen Parse developers mention improved caching of Parse objects coming at some point in the future. However, this feature does not exist yet and there is no knowing when it will come. In the mean time, if you want to support offline use you have to use Core Data or some other local store. FTASync (which I have never used) is designed to sync Parse objects with Core Data:
https://github.com/itsniper/FTASync
You could also write your own code to sync the two sets of data.
The Parse iOS/OSX SDK provides a local datastore which can be used to store and retrieve PFObjects, even when the network is unavailable. To enable this functionality, add libsqlite3.dylib and call [Parse enableLocalDatastore] before your call to setApplicationId:clientKey:.
As stated in the Parse documentation:
You can store a PFObject in the local datastore by pinning it. Pinning
a PFObject is recursive, just like saving, so any objects that are
pointed to by the one you are pinning will also be pinned. 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.
You don't need to worry about it at all.
PFObject *gameScore = [PFObject objectWithClassName:#"GameScore"];
gameScore[#"score"] = 1337;
gameScore[#"playerName"] = #"Sean Plott";
gameScore[#"cheatMode"] = #NO;
[gameScore pinInBackground];
If you have multiple objects, you can pin them all at once with the
pinAllInBackground convenience method.
[PFObject pinAllInBackground:listOfObjects];
Retrieving an object from the local datastore works just like
retrieving one over the network. The only difference is calling the
fromLocalDatastore method to tell the PFQuery where to look for its
results.
PFQuery *query = [PFQuery queryWithClassName:#"GameScore"];
[query fromLocalDatastore];
[[query getObjectInBackgroundWithId:#"xWMyZ4YE"] continueWithBlock:^id(BFTask *task) {
if (task.error) {
// Something went wrong.
return task;
}
// task.result will be your game score
return task;
}];
Any PFQuery can be used with the local datastore just as with the
network. The results will include any object you have pinned that
matches the query. Any unsaved changes you have made to the object
will be considered when evaluating the query. So you can find a local
object that matches, even if it was never returned from the server for
this particular query.
PFQuery *query = [PFQuery queryWithClassName:#"GameScore"];
[query fromLocalDatastore];
[query whereKey:#"playerName" equalTo:#"Joe Bob"];
[[query findObjectsInBackground] continueWithBlock:^id(BFTask *task) {
if (task.error) {
NSLog(#"Error: %#", task.error);
return task;
}
NSLog(#"Retrieved %d", task.result.count);
return task;
}];
When you are done with an object and no longer need it to be in the
local datastore, you can simply unpin it.
[gameScore unpinInBackground];
There's also a method to unpin several objects at once.
[PFObject unpinAllInBackground:listOfObjects];
For more information on using Parse's local datastore check the Local Datastore documentation provided for iOS/OSX on parse's website.
No it can not. It's no where near the same, I suggest https://github.com/itsniper/FTASync

Resources