Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data: statement is still active

Tags:

ios

core-data

I am getting the following error in my app:

CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. statement is still active with userInfo (null)

Everything that I can find seems to indicate the I may be having multi-threading issues with my core data managed object context, but I can't seem to find anywhere in my app where this would be the case. I am accessing and managing a managed object context on a background thread. The context is only fetching and manipulating objects on that one background thread. When I detect saves to that context through NSManagedObjectContextObjectsDidSaveNotification, I am merging the changes into a different context that I only access on my main thread. When I make the call to merge the changes, the error is thrown. It is very rare that this occurs, even with the same data sets.

I read somewhere that it is possible to 'enable multi-threading assertions' using '-com.apple.CoreData.ThreadingDebug 3', but I haven't been able to get this to work. Does anyone know if this is possible? I was hoping this might turn on some assertions that would help me find where I am playing with the context on the wrong thread or something.

Any other clues on what might be happening or how to track this sort of problem down?

like image 609
toofah Avatar asked Oct 25 '11 01:10

toofah


1 Answers

I had a similar problem and found a way to solve it.

I've created a mechanism creating different contexts based on thread names (1 thread = 1 context).

#include <pthread.h>
...

    mach_port_t threadID = pthread_mach_thread_np(pthread_self());
    NSString *threadName = [NSString stringWithFormat:@"%x", threadID];
    NSManagedObjectContext *context = [singleton.threadsContexts objectForKey:threadName];
    if (!context) {
        NSLog(@"Creating managed context for thread named '%@'", threadName);
        context = [[NSManagedObjectContext alloc] init];
        [context setPersistentStoreCoordinator:[singleton.managedObjectContext persistentStoreCoordinator]];

        //initialize dictionary in your singleton if it as not been yet
        if(!singleton.threadsContexts)
        {
            singleton.threadsContexts = [NSMutableDictionary new];
        }
        [singleton.threadsContexts setObject:context forKey:threadName];
    }

    return result;

and then, when i need a full version of a managed object in a background thread, I get a copy of the object dedicated to this thread :

NSManagedObjectModel *myNewObject = [myBackgroundContext objectWithID:[myObject objectID]];

Hope this answer will help.

like image 119
Dirty Henry Avatar answered Sep 27 '22 21:09

Dirty Henry