Memory leak into permanent storage - iphone

I have inherited code for an iPhone app using Core Data written by another team. In looking at the relationships between objects and how the objects are created/used in code I came to the realization that there was a memory leak into permanent storage. Sure enough when I delete all the top level objects out of Core Data there where objects left behind. Whats more there was an operation where the values/relationships of one object where copied to another and this left orphaned objects in Core Data.
I have since fixed the problems and there are no longer any new orphan objects being stored in Core Data. The problem now is how do I removed these orphan objects from the permanent storage of existing users that have been using the leaky app for who knows how long?
My initial thought was to copy the top level objects to another ManagedObjectContext. Then delete all the objects out of the original context. Finally copy the top level objects back into the original context. Does anyone see any problems with this or have a better idea?

Orphaned objects should have an empty relationship so you could just fetch on that empty relationship and delete the returned objects.
You probably want to update the data model to prevent orphaned objects. Orphans are usually a sign of a badly designed model. Make sure all relationships have a reciprocal and, when appropriate, make a relationship required. You can also add validation to prevent orphans.

Related

How to deal with Core Data retain cycles

The core data guidelines recommend that you model your relationships with an inverse. No problems there.
Interestingly though if you Load an object A that has a to many relationship to B and walk the object graph you end up with a retain cycle and the memory is never freed.
For a simple object graph you can just call refreshObject:mergeChanges: on A to re-fault the object so that relationships are no longer strong references.
If you have a complicated object graph though this is a pain because you need to call it on every object you have touched. It seems like a pretty important consideration when using core data yet there is only one paragraph on this topic in Apples documentation.
I am just wondering how other people handle this? A long running app would slowly just consume more and more memory without some sort of manual process to force objects to revert to faults.
Are there any known patterns for dealing with this. I'd imagine so since lots of people use Core Data I just can't find any recommendations
You are ignoring several aspects of core data when making your assertions. If you fetch an object, let's say object A, which has a one-to-many relationship to object B, when you fetch A, you will have all the objects on B which are related to A. A one to many relationship creates the list of objects related to A and contains them on an NSSet property of your NSManagedObject subclass. Note that these objects are in a faulted state, and the memory footprint from this is insignificant. If you manipulate the objects in the relationship, core data will unfault these objects when necessary. You do not have to do anything to get this behavior. If you want to trigger the faulting behavior yourself to send the objects to fault again, you can use refreshObject:mergeChanges:. If you do not send them back to fault, the faulting behavior will be trigger again eventually.

What is the most efficient way to remove all instances in an entity in Core Data?

I found from this post I can remove all instances of an entity by fetching them all and deleting them all.
Isn't there any more efficient way to do removal? My consideration is I will have thousand of records within that entity.
There's no more efficient way, because CoreData is an ORM layer, not a database. Therefore you deal with objects and if you want them gone, you have to delete them.
A trick you may want to investigate is creating a parent object that would have a one-to-many relationship with the objects to delete. You could basically have only one of those that points to every entry in your big table. Set the cascade delete option on the relationship in your model. Then when comes time to purge, you just delete the parent object. Because of lazy loading, it won't try to load your other objects.
This being said, I haven't tried it myself, but it seems like a viable option.
In a special case where all instances of this entity are self-contained, it would be quicker to delete the backing file and re-initialize the management objects. This only works if your data can be arranged so that the temporary stuff is within its own store.
Otherwise, you'd probably get better results by using direct database access instead of core data.

Create a Core Date Entity Instance But not want it to be stored(non-persistent)

Sometimes I need instantiate CoreDateEntity to store some infomations for temporarily using.
But I needn't it be stored into DB.
currently I created a similar class which have same structures as the CoreDateEntity does.
It works well but I have to do many datas transfer between Two models.
Is there any better way to handle this?
Thanks for all the replies. but you guys just give me half answer of this. consider about this, I need place some entity without MOC into current database pool, how could I do this? I already checked the documents of CoreData, seems I didn't find API to transfer one entity from MOC to another MOC(manage object context).
According to Apple docs you can initialize a managed object without context if you specify nil as context.
- (id)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)context
You can assign entities to different stores when you set up the data model. Have one store be the persistent store and the other an in-memory store. You can't form relationships across stores but it sounds like you don't need that.
To assign a configuration, hit the configuration tab (the one with the wrench icon) in the entity detail (where you give it its name, class and parent). When you create the persistent store, add the configuration name to the options dictionary.
Update:
I think you maybe overcomplicating things. It sounds like you have some managed objects that will be temporary and some that will persisted but sometimes you may want to save the temporary objects. I don't think you should bother trying to separate out the "temporary" objects. Doing so just adds complexity without any performance benefit. Instead, just use ordinary persisted objects and then delete the ones you don't want.
Always try the simplest solution first.
Use two different managed object context's and only save the objects from one context. Be careful not to set relationships between objects of two different context's - this doesn't work.

Core Data performance deleteObject and save managed object context

I am trying to figure out the best way to bulk delete objects inside of my Core Data database.
I have some objects with a parent/child relationship. At times I need to "refresh" the parent object by clearing out all of the existing children objects and adding new ones to Core Data. The 'delete all' portion of this operation is where I am running into trouble.
I accomplish this by looping through the children and calling deleteObject for each one.
I have noticed that after the NSManagedObjectContext:Save call following all of the deleteObject calls is very slow when I am deleting 15,000 objects.
How can I speed up this call? Are there things happening during the save operation that I can be aware of and avoid by setting parameters different or setting up my model another way? I've noticed that memory spikes during this operation as well. I really just want to "delete * from".
Thanks.
Supposing that you have in your Core Data model a parent and a child entities, and the parent has a to-many relationship to child called children, you should be able to delete all of the child objects without looping as follows:
NSManagedObject *parentObject = ...;
[parentObject setValue:nil forKey:#"children"];
or using the Core Data generated method
- (void)removeChildren:(NSSet *)value;
NSSet *children = [parentObject valueForKey:#"children"];
[parentObject removeChildren:children];
I am not sure if this will speed up the NSManagedObjectContext save operation. Please let me know about the performances.
Check the relationship dependency graph: a cascade of deletes triggered by the initial deletion will slow things down. If those deletes are unnecessary then change the deletion rule.
according to apple website : http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdCreateMOs.html
it is very simple :
Deleting a managed object is straightforward. You simply send its managed object context a deleteObject: message, passing the object you want to delete as the argument.
[aContext deleteObject:aManagedObject];
This removes the managed object from the object graph. Just as a new object is not saved to the store until the context is saved, a deleted object is not removed from the store until the context is saved.

Can we use union of two sqlite databases with same tables for Core Data?

I have an iPhone Core Data app with a pre-populated sqlite "baseline" database. Can I add a second smaller sqlite database with the same tables as my pre-populated "baseline" database but with additional / complementary data such that Core Data will happily union the data from both databases and, ultimately, present to me as if it was all a single data source?
Idea that I had is:
1) the "baseline" database never changes.
2) I can download the smaller "complementary" sqlite database for additional data as and when I need to (I'm assuming downloading sqlite database is allowed, please comment if otherwise).
3) Core Data is then able to union data from 1 & 2. I can then reference this unified data by calling my defined Core Data managed object model.
Hope this makes sense.
Thanks in advance.
Core Data is designed to handle multiple data files via the – addPersistentStoreWithType:configuration:URL:options:error: method. This will allow you to combine all of the data files together and then access them via a single NSManagedObjectContext.
Your only issue, and it may not even be an issue for you, is that the store files cannot directly reference each other. Therefore you will need to reference data between files "manually" via unique identifiers. However I suspect you are already aware of that limitation.
Manual Relationships
The idea is that when both objects in a "relationship" are in one model and one file, Core Data does its magic and handles all of the referential integrity for you. However when they are in different files and/or models this doesn't happen automatically anymore.
The solution to this issue is to use a fetched property that looks up some unique identifier to retrieve the entity (or entities) that you want to be on the other side of the relationship. This will give you a "weak" relationship between files.
One thing to note though when doing this. The fetched property does not get updated automatically when something changes. This means when data changes that would cause that relationship to change, your application will not be automatically made aware of it and you will need to request that property again to get the updated relationship information.
Hopefully that makes it a bit clearer.
Co-existance of fetched properties and relationships
They can definitely co-exist but realize that they are two separate properties. If you want your controller code to see them as one, then I would suggest building a subclass for that entity and then adding a convenience method in there that hits both the relationship and the fetched property and then rolls them up into one NSArray or NSSet before returning it back to your controller code.
You can attach the downloaded database with ATTACH DATABASE statement and operate with unions of tables.