Coredata safe clear subEntities - ios

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...).

Related

Reset new coredata managed object to a staged state

Hi fellow iOS developers, I have seem to run into a roadblock here with coredata and Im fairly certain this is should be a common use case. But I am either not querying google correctly or my design with handling managed objects was bad which led to this problem.
So basically, the problem that I am facing is the following..
User creates a new managed object object.
User updates said new managed object object (say edit the name
field)
** The following is the problem **
User wants to edit the same field again, but decides to discard their changes
What is the right thing to do here? Initially I was using .refresh() on the managed object context, but that only works if the object is persisted in the database.
Essentially, I don't want to save the object until the user explicitly opts to "save". Which leaves me in this limbo land. At first one of my thoughts was to created regular objects and convert them into core data objects when "save" is selected. However, that proved to be inefficient especially when handling multiple relationships.
I would think that there is something that is provided that aims to solve this problem, im just not quite querying google correctly.

Parse's CurrentUser doesn't keep refreshed data

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.

Save data in two persistent stores

I am having an app where there is a search feature that does a network request. However uses the same model framework as the entire app.
This means that when the user searches for something I need to create managed objects from the found data, save them and display them. However this messes up old records with the user recent data.
I would ideally like to save the managed objects found in the search in a separate in-memory persistent store so it doesn't make disorder in the main data.
I haven't done something like this before so what is the best way to approach it?
Thank you!
As has been suggested by #stevesliva, you do not need to involve yourself into the complexities of maintaining multiple partially in-memory stores. The way to go here is to create a child context and fetch the online data into this context. Once you do not need the data any more, just discard the context.
If you decide to save the downloaded data, you can simply "push" the changes to the main context via save:. At that point you could make necessary adjustments to the data so they fit into the user data. Depending on your model, one feasible solution could be to create another attribute on one of the entities that marks linked objects as distinct from the user created objects.

Does entity relation also get loaded into memory when entity gets fetched in CoreData?

I'm working on an app that allows the user to create a little comic from a photo. I've implemented CoreData so the user can save and reedit their comic. I've created two entities: ComicInfo and ComicDetails which have a relationship with one another (I did it this way from reading the Ray Wenderlich tutorial). So when the user saves a comic, I make a new ComicInfo NSManagedObject, store the name and thumbnail in it, then I create a ComicDetails NSManagedObject, store various attributes in that, and I store the ComicDetails in the ComicInfo and save.
I've created a UITableView that displays the thumbnails and names from all the ComicInfo objects to allow the user to select one so they can edit the comic.
What I'm wondering is, why did I separate this into two entities instead of just doing them in one? I'm assuming that when I load all of the ComicInfos from CoreData, that the ComicDetails will also be loaded into memory, or am I wrong about that? In a perfect world, I'd like it so only the ComicInfos are loaded when the UITableView is launched, then when the user selects one of the rows, the associated ComicDetails will then be loaded into memory. Is that not what's happening here?
The reason to have two entities is to get the behavior you're hoping for. In general when you do a Core Data fetch, only instances of the entity type you request are loaded into memory. Related objects are not immediately loaded. Instead, Core Data loads them automatically on demand.
In your case, if you fetch ComicInfos, only ComicInfos get loaded. But if you take one of those objects and access its details attribute, the related ComicDetails instance is automatically loaded, without needing to do another fetch. The related objects are only loaded when you ask for them. So, you're getting the behavior you want.
If you ever want to override this behavior, you can use setRelationshipKeyPathsForPrefetching: to force NSFetchRequest to load not only the objects you actually fetch, but also specific related objects as well.

storing number of yet nonexistent objects in relationship in Core Data

I have some data that needs to be loaded from the server (backend). For example, let's just say I have an entities of user and event. The relationship between them is many-to-many (user can attend many events and event can have many attendees). All the data is stored remotely on backend and locally in Core Data. When I download data from backend I convert it into NSManagedObjects and store it in NSManagedObjectContext. Everything's very simple, but...
When I download a list of events I want to know, how many attendees this event has. But I cannot download a list of users in the same request, because it's totally overkill. What I need is to download, let's say, a list of users' unique ids so that I can have two things: total number of attendees and means to download detailed data of concrete users (via unique id). Or there's another example: I need to know total number of attendees and download a limited set of them, so I can create some entities in CoreData, but not all of them.
So the main question is how am I supposed to store such information in my CoreData? Meaning I need to know that for some entity there are some related entities in relationship that are not actually currently present in CoreData, but I know how many of them there should be. The first thing that came in my mind is to have a attribute called something like usersCount in my event entity, but that seems to be kind of dirty. What is the best practice for such situation?
Please comment if the question is not clear enough so I can maybe add some more specifics.
When you download an event with a list of corresponding user ids, then you can create
the Event object and also the related User objects, but you fill only the "userId"
attribute in the user object.
Later, when you download the complete user info, you update the existing (incomplete) objects
or create new user objects. Implementing Find-or-Create Efficiently in the "Core Data Programming Guide"
describes a pattern that might be useful.
So the idea is to create Core Data objects with incomplete information first and update the
objects with detailed information later. The advantage is that you can set up all relationships immediatly, and e.g. counting related users works even if the user information
is yet incomplete.
There is nothing dirty about having an attribute to store the count, especially if those entities are retrieved and paged via separate requests.

Resources