I'm using CoreData (with SQLite as the store) in an iOS 4 iPhone application to store data that i initially retrieve from an xml file. My data model contains more than 15 entities and I am concerned about memory consumption since I saw CoreData creating all the NSManagedObject in memory to represent the object graph of my data model. I parse the xml file with a SAX libxml2 based parser and try to store each 'agglomerate set' of entities together chunk by chunk, but i'd like to release each managedobject after this agglomerate has been inserted and the managed context saved, in order to save memory for the next agglomerate. I saw that i have to use refreshObject: mergeChanges: to counterbalance the multiple retain each object has received while associated to others by relationships (as designed in the data model). I do that after saving the context, but next when I try to look up again in the store trying to fetch what I inserted before it returns nothing. Am I missing something?
I think you have to do this for every change
NSManagedObjectContext *moc;
NSError *error;
[moc save:&error];
Otherwise it will be discarded
If all you do is importing (e.g. you don't need to keep the inserted objects to display to the user and so on), you can simply use [moc reset]
after the save. So the algorithm would look something like this:
NSManagedObjectContext* moc = ...;
while ([xmlData hasMoreObjects]) {
// Create e.g. 500 objects and insert them into the managed object context
NSError* error = nil;
if (![moc save:&error]) {
// handle the error
}
[moc reset]; // Here the inserted objects get released in the core data stack
}
Resetting the managed object context does the same as if you would refresh every object (as you did before). Also you should consider using the [[NSManagedObject alloc] initWithEntity:insertIntoManagedObjectContext:]
instead of the convenience methods on NSEntityDescription
, because you can release them just after you don't need them anymore, and they won't stay in memory until the autorelease pool gets cleared.
Take a look at the Core Data Programming Guide, as it contains a whole section centered around efficiently importing data and one about memory management with Core Data.
You can't directly/manually manage the memory of managed objects because the context has control the lifecycle of the objects to maintain graph integrity.
If you can process the import in discrete chunks, save the context after each chunk followed by:
[context refreshObject:theObject mergeChanges:NO]
... which will convert the newly saved objects into faults so they take up very little memory.
You only need faults to set relationships with so the objects processed in the previous chunk will still be available to set in relationships in the current chunk.
Whenever possible, I create objects in one pass, save them, convert them to faults and then set relationships in the next pass. This is not always practical if you have a required relationships.
You might want to check out the Core Data Programming Guide:Efficiently Importing Data if you haven't already done so.