How to use Parse cached query in offline mode? - ios

I am trying to use a cached user query as explained in Parse documentation:
PFQuery *scoresQuery = [PFUser query];
[scoresQuery orderByDescending:#"score"];
[scoresQuery whereKey:#"fbId" containedIn:meAndMyFriends];
scoresQuery.cachePolicy = kPFCachePolicyNetworkElseCache;
When network is available the query is cached, and [scoresQuery hasCachedResult] equals YES
However, if I turn to "flight mode" and restart the app, the query is not found in cache.
Is there a way to make it persistent?

Related

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

PFQuery, hasCachedResult() always retuning false?

Currently trying to just check if the query has cached inside PFQueryTableViewcontroller, using a simple if statement but regardless it keeps returning false, even when i turn internet off and can access page through cache.
var query = PFQuery(className: "Tasks")
var isInCache:Bool = query.hasCachedResult()
println(isInCache)
query.cachePolicy = PFCachePolicy.CacheElseNetwork
return query
Trying to just simply us an if statement checking internet and and if there is a cache. If anyone has any workarounds this would be really helpful been on this a while now

Parse doesn't return PFObject

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.

Does not show/retrieve PFObjects that were created by another Parse Installation user

I've been working on an app for months, and in the development stage it was having no problem retrieving info from the Parse backend. However, the second that I moved the app over to distribution and put in on the app store, I discovered that all the objects that someone would send me from their installation would not show up in my inbox. I am only able to see the objects I created in my inbox. Would anyone know possibly why I can't see objects that other users make on my app, and Vise Versa? Btw, this is through Xcode, Objective-C, and iOS.
In the Parse data browser, check the ACL on the objects you expect to see but don't. You are probably creating objects that are not publicly readable. You need to set a publicly readable acl on those objects.
PFObject *pfObject = [PFObject objectWithClassName:#"MyClass"];
PFACL *acl = [PFACL ACL];
[acl setPublicReadAccess:true];
pfObject.ACL = acl;
[pfObject saveEventually];
You can also set up a default ACL somewhere in your app, possibly in your AppDelegate.m right after you intialize parse, so you don't need to create an ACL every time you create an object:
// Connect to Parse
[Parse setApplicationId:#"app-id" clientKey:#"client-key"];
// Set the default ACL
PFACL *defaultACL = [PFACL ACL];
[defaultACL setPublicReadAccess:YES];
[PFACL setDefaultACL:defaultACL withAccessForCurrentUser:YES];
If that isn't your issue, post some code as well as the ACL for an object you expect to see but don't.

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