Search code examples
iphoneioscore-dataios6

NSManagedObjectContext Batch Save Limit


I'm currently working on an iOS app using CoreData.

When the app is started for the first time a series of web requests are made against RESTful web service.

The web service serves up a series of json responses which can contain upwards of 2000 records.

These records are then parsed, transformed into various core data entities and stored within our SQLite persistence store.

Once this operation is complete we create an object graph by fetching all the rows within Entity A (for example) and create an object graph we use at a later time.

For some reason, while iterating through all NSManagedObjects stored within Entity A some NSManagedObjects have missing property values.

Given that we're working in a multi-threaded environment, we've made sure that we're creating separate managedObjectContexts on separate threads - however, during our most recent test runs, we've configured the environment such that only one thread is saving/retrieving data from the SQLite persistence store at a time.

It may also be worth noting that we don't perform a [context save:...] operation until we've parsed all 2000+ records that have come back in a json response.

After some trial and error, I've noticed that the problem goes away is we perform a save every insert.

For example, the following code will work ok:

NSManagedObjectContext *context = ...
NSError *error = ...

for(id record in collectionOfRecords){
    //create entity for insertion
    [context save:&error]
}

But this will cause the issue of missing property values:

NSManagedObjectContext *context = ...
NSError *error = ...

for(id record in collectionOfRecords){
    //create entity for insertion     
}
[context save:&error]

Question:

Is there a maximum number of NSManagedObjects that can sit in memory before an [NSManagedObjectContext save:...] operation must be performed?


Solution

  • To answer your question as asked: There is no set limit on how many managed objects can be in memory before a save is needed. Your application can create managed objects without saving as much as it wants, when memory is running low you will start to get the normal memory warnings that any iOS application can get. Ideally you do not want this to happen, and doing a context save or a context reset in reaction to a memory warning is probably not a very good idea either.

    The scenarios you are describing in your details, however, are covered by Apple's documentation:

    Core Data Programming Guide: Efficiently Importing Data

    And there is more that is relevant here:

    Core Data Programming Guide: Core Data Performance

    In your case, you should be saving more often, and be doing work on more than one thread - you say you are only accessing storage from one thread, that is probably a large part of your problem right there. You do not seem to be getting changes from the context on thread A in the context on thread B - NSManagedObjectContextObjectsDidChangeNotification is the primary way of doing that when using the older thread confinement model.