Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

trying to save NSManagedObjectContext not working

I have been trying to figure out this problem for 2 days now. I keep getting an error when I try to save.

//self.data is NSManagedObject. kAppDelegate.moc is the managed object context.
self.data = [NSEntityDescription insertNewObjectForEntityForName:@"Data"
                                 inManagedObjectContext:kAppDelegate.moc];

[self.data setValue:[NSNumber numberWithBool:NO] forKey:@"isit"];
[self.data setValue:@"" forKey:@"name"];

NSError *error;
if(![self.data.managedObjectContext save:&error])
{
    NSLog(@"Save did not complete successfully. Error: %@",
    [error localizedDescription]);
}

When I run it though, this appears in the console:

"CoreData: error: Mutating a managed object 0x10935d4c0 (0x10935d420) after it has been removed from its context."

And this:

Save did not complete successfully. Error: (null)

I can't figure out why this is happening, or why the error is "null".

like image 859
user3251270 Avatar asked Jul 25 '14 22:07

user3251270


2 Answers

Given this error:

2015-07-06 06:15:05.124 xxx[3609:796500] CoreData: error: Mutating a managed object 0x17423d3e0 (0x1740d0450) after it has been removed from its context.

Found:

In my case; a trace of the initialization sequence (using breakpoints and log message class_initial:%B:%H) revealed that I was creating the context twice. My solution was to simply redirect the redundant call to self.managedObjectContext. I may take time at a later point to track down and eliminate the redundant logic.

Initial Results:

  1. d: init(modelName:):1
  2. mext: findInStore(_:):1
  3. mext: findInStore(_:sortDescriptors:predicate:):1
  4. mext: NSManagedObject:1
  5. d:context DataStore:1
  6. d:persistentStoreCoordinator :1
  7. d: managedObjectModel:1
  8. d: applicationDocumentsDirectory:1
  9. mext: createInStore(_:):1
  10. mext: NSManagedObject:2
  11. d:context DataStore:2

Final Results

  1. db: init(modelName:databaseName:):1
  2. d: init(modelName:):1
  3. mext: findInStore(_:):1
  4. mext: findInStore(_:sortDescriptors:predicate:):1
  5. mext: NSManagedObject:1
  6. d:managedObjectContext managedObjectContext:1
  7. d:persistentStoreCoordinator :1
  8. d: managedObjectModel:1
  9. d: applicationDocumentsDirectory:1

Recommendation:

For others having this problem, I recommend a close inspection of your Core Data Stack's initialization sequence. A context may be created twice or the managed object might be getting deleted.

like image 113
Tommie C. Avatar answered Oct 21 '22 03:10

Tommie C.


There is another way to provoke the "CoreData: error: Mutating a managed object ... after it has been removed from its context." message.

  • If you have a multiple layer core data stack
  • You hold a strong reference to a managed object in the foreground
  • A background thread updates that same core data object

When the update bubbles up to the foreground thread it invalidates your object. You need to detect that and retrieve the new version.

Hold a weak reference in a cache object. Then write a getter that checks that cache object for nil and retrieves the new version of the object.

weak var cachedObject: NSManagedObject?

var object: NSManagedObject {

    get {

        objc_sync_enter( self )
        defer {

            objc_sync_exit( self)
        }

        guard nil == cachedObject else {

            return cachedObject!
        }

        guard let object = // **** retrieve object here ****

            fatalError( "managed object does not exist" )
        }

        cachedObject = object

        return cachedObject!
    }

    set {

        cachedObject = newValue
    }
}

Or, you could just retrieve the object every time in the getter.

like image 28
Bob Wakefield Avatar answered Oct 21 '22 02:10

Bob Wakefield