Parse's CurrentUser doesn't keep refreshed data - ios

Using Parse for iOS, I modified the _User's table to have a field called "Friends" which is an array of pointers to other _Users (by the way, I also have other additional fields).
When I call PFUser.currentUser(), I don't see this friends field in the user object. So I call PFUser.currentUser().fetch() (because refresh method doesn't seem to exist anymore) and I finally have the friends field in my currentUser object.
However, as soon as I exit the app, this field is lost. It doesn't seem to be saved locally unlike all the other fields of the current user.
How am I supposed to force a refresh of the cached current user ?

According to parse.com itself and one of their posts, there is no other way to keep your user up-to-date:
saveEventually does not write through any caches at this time,
including the currentUser, if the app has been restarted. You'll need
to regularly call fetch to keep it up-to-date. We are aware that this
is inconvenient, and are looking into ways to make it work better for
you.

Are you sure that you want your user objects to contain a value that's an array like that? I obviously don't know your use application, but I would recommend using a PFRelation instead. It works just like an array, but the Parse Framework provides a bunch of additional functionality along with it.
As for your specific question it might have to deal with Parse. Maybe they don't automatically retrieve and save arrays that are on an object. That would be my guess because an array could contain who knows how much data in it. I still don't know why they wouldn't locally save that data after it's fetched.
My suggestion is probably a little over the top, but would most likely be the best outcome. Utilize a local database such as CoreData or even the ParseLocalDatastore. Then encapsulate the Parse framework to have your own User object where you can store the information, which can also maintain persistence via your database.

Related

Coredata safe clear subEntities

I want to ask for a safe way to clear subEntities in coredata.
I have my a many-to-many relationship like this: Product *<->* Product. Therefore, I've got to create a subEntity to hold some special values between (sortPosition, groupName.....).
So it's like this: Product *<->1 ProductSubEntity 1<->*Product.
When I download products from server's API, the easiest way to update correctly correspond to the server's result is:
Remove all child relationship ([self removeProductSubEntities:self.subEntities]).
Add sub from server's result.
Result: There'd be a lot of subEntity in coredata (which won't hold relationship to any product), and this might take storage/memory/cpu when CRUD (I think?). But I can't actual delete the subEntity (in case it's being hold reference to as an viewController's Object somewhere, and it might cause crash: access to a deleted object).
QUESTION:
How can I clear those sub entities (might occur sometimes) if:
No relationship to any product.
No actual reference from anywhere (any viewControllers or objects)???
P/S: I'm thinking of implement a batch delete when terminate app. Could that be consider a safe solution?
I don't consider this to be a datastore issue, rather a UI update issue. You should delete the objects from the datastore when you don't need them any more and you should update the UI accordingly.
1 thing you didn't mention is re-use. It's possible that your download may be an update to an existing item, which you could find and update, then life is easy all round. Arguably everything below still applies in this case though as your UI might not update to reflect changes and you may need to refresh the managed object.
For the UI update it's generally wise to observe the datastore for changes, usually with an NSFetchedResultsController. If you're doing this then your UI would automatically update itself with the changes.
If you're explicitly passing entity instances around then you should have some way to trigger an update explicitly, and exactly how that works depends on your UI. Generally speaking you'd be doing something like posting a UINotification to tell the system that the datastore changed and they need to re-validate their data objects. For the UI you shouldn't be showing now-dead objects to the user, and in your question where you talk about not deleting to avoid crashes, it's probably worse to allow the user to update invalid objects and just quietly not telling them that their updates won't be saved. When the notification is received you may want to pop a (some) controller(s) off the stack, or re-query the datastore for the new data to be displayed.
If for some reason you don't want to do the above, then yes, you can query for all of the entities with a nil relationship and then batch delete them. This should be done on a background thread just like data loading and I'd recommend doing it on app load instead of close (because you won't have so many view controllers loaded and the ones that are should all have only valid references now...).

Pulling Data of Pointer Field of PFUser.currentUser in Parse

I am writing an iOS app with Swift using Parse.
In my User table, I have a pointer field called UserAddress which is pointing to an Address table record. I would like to pull this Address data for current user. I did a bit of research and figured out fetching in background is an option but I would like to avoid it. Is there an alternative to pull this data without running extra fetch work?
What I can imagine is:
Fetching pointer data in AppDelegate before the app gets ready to use for users.
Somehow, force to set includeKey when loading a currentUser
Any of the above is feasible? Please advise me.
You correctly understand the two options, and they are the only two options. For non-user objects, usually includeKey() on a query is the way to go.
For the current user, since you have the user already, it would seem a little strange to query the user, including the pointer, just to avoid fetching the pointer, but that would work. You might be better off working on whatever's making you hesitant to do the fetch().

Keep reference of ABPerson in CoreData

I'm trying to keep the phone's contacts in my app up to date, in a persistent way. For that I'm thinking of using Core Data.
My plan right now seems highly suboptimal :
Browse the address book and every ABPerson in it
Store every field in a CoreData persistent store
Store the image in a separate file with an unique name and a reference in another "Contact" field.
And I do this every time the app comes in foreground in case the user would change one of his contact's name or picture, etc.
Some of my users have more than 2500 contacts, sometimes the operation lasts up to 10 seconds.
My question is :
Is there a way to keep some kind of reference to my ABPerson in coredata, so I can always load my ABPerson properties everywhere instead of Contact properties? (which would then always be up to date).
And I'm not even sure it's the right decision :
Should I always use the ABRecord that I find with a reference?
Should I always use my own copied data that I update regularly (from the ABAddressBook)?
If not, do you guys think I'm doing this in a decent way or would you suggest something else?
EDIT:
As asked in the comments:
I need to keep the contacts up to date simply to use their firstname, lastname and picture properties. If I notice the ABRecord changes, I'll update the related custom objects accordingly and that's it. I won't really need anything else afterwards (until they're edited again)
Thanks
Obtain and store only the ABRecord's unique identifier value. This is the one persistent way to reliably refer to the same person repeatedly and consistently.
You can always get all the other info out of the contacts database by using this unique identifier.
In iOS, call ABRecordGetRecordID to obtain the person's unique ID. Store that. When you later want to obtain the corresponding person, call ABAddressBookGetPersonWithRecordID.

RESTkit, CoreData: process object right before trasferring it to CoreData

I have a problem.
I have iOS client app that has to allow multiple users to log in and store their data locally.
Data is synchronized with RESTful service, and the latest snapshot along with user's changes should be stored locally for all users.
Previously this app was implemented with SQLlite as data storage engine.
Now I would like to migrate to CoreData.
What do I have:
server returns me entities for current user. User ID is not sent, as the user authorizes and gets their session;
I know who is logged in an should store all data for this particular user. In order to do that I need to say CoreData to store the object for the user with ID=12345.
The problem is:
I have to tell CoreData to store the particular object associated with particular user's ID.
I need a way to somehow alter the object mapped with RESTkit - setting proper ID field for it.
This task was straight and simple with SQLlite but looks problematic with CoreData.
I am still thinking that I don't know something about CoreData asking you to help me with clarifications or useful links.
There isn't a good way to do it.
Hacky, you could add the id as a parameter in the request so you can map it back again (requires RestKit dev branch at time of writing).
Non-hacky is to update and re-save the objects returned in the mapping result.
Alternatively you could use one operation to download the JSON, then mutate it, then run another operation to map it.

Best way to preload nsmanagedobjects

i want to store some managed objects as to make searching later on easier, what is the best way to do that? (So that it survives exiting the app)
I am thinking user defaults (but im not sure if you can store managed objects like this)
Or some sort of cache?
SO, although I am not sure this is the best way to do it, here is how I fixed this issue. I was looking for a way to preload a list of results that would persist through launches.
To accomplish this I created an NSMangedObject, called it HistoryObject, and added a relationship (to-many) to the object I wanted to store. I added those objects to this object (basically an NSManagedObject array of objects), and retrieve this object whenever I want to load the subObjects...

Resources