Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Odd behavior while managing multiple data stores #270

Closed
Marxon13 opened this Issue · 26 comments

8 participants

@Marxon13

I'm trying to convert multiple databases (made of plist files), into multiple core data databases, and am experiencing some odd behavior. (especially after the commit on Oct 2nd).

I'm converting the databases with a loop preforming in a background thread and in the main thread;

  • I start in the background thread, creating a stack with setupCoreDataStackWithStoreNamed:.
  • Then I add all of my entities and save in the background thread.
  • Calling back to the main thread I preform [MagicalRecord cleanUp]; and release the background thread.
  • If I need to convert another database, I recreate the background thread, and preform these actions again.

First, [MagicalRecord cleanUp] is not tearing down and deallocating the entire data stack. The same NSPersistentStoreCoordinator is reused each loop, and one the same three NSManagedObjectContexts that are created are reused each time. If I use NSLogs to check the values of these objects in MagicalRecord.h, they are set to nil after cleanUp, but during the start of the next loop they are recovered, and used again. Causing each separate database being saved to be saved to the first store that is created, and ignoring the last created store.

Second, [NSManagedObjectContext MR_resetContextForCurrentThread]; or any similar reset method is not "forgetting" all of its NSManagedObjects. And when the context gets reused, all of the data from the previous database still exists.

Third, before the October 2nd update, directly after calling [managedObjectContext MR_saveNestedContexts]; I was able to preform [NSManagedObjectContext MR_resetContextForCurrentThread]; immediately afterward without error. After October 2nd, If I reformed this method, on the next loop I would get an assertion failure *** Assertion failure in +[NSManagedObjectContext MR_defaultContext]

Before this update it was my understanding that when MagicalRecord saves on a background thread, it copies the NSManagedObjectContext being saved. So I can edit the context after saving, and nothing would happen to the saving context. Has this changed?

I tried to make this issue as non-application specific as I could. If you want to see what I'm doing specifically, I have a stackOverflow question with my code: http://stackoverflow.com/questions/12700590/switching-between-core-data-stores

@blackgold9
Collaborator

A few thoughts
#1 - Are you using different models per store? If not that simplifies things

#2 - the change on oct 2nd made saveNestedContexts asynchronous, BUT adds a variant taking a completion callback. Calling reset THERE should be safe. In your case you'd need to reset both the defaultContext and the rootSavingContext

#3 - You could attempt to use removePersistantStore on the default persistance store coordinator to remove the existing one, and then add the new one, so you would only have one store in the coordinator at a time. Calling cleanup wouldn't be necessary, but you would need to call reset on the 2 contexts i mentioned before. You could also use assignObject:toPersistentStore: to be sure it goes to the right store.

#4 - how are you doing background work? saveInBackground?

@Marxon13

#1 I am not using different models, I let MagicalRecord load it automatically from the app bundle.

#2 I replaced [NSManagedObjectContext MR_resetContextForCurentThread]; with
[NSManagedObjectContext MR_resetDefaultContext]; [[NSManagedObjectContext MR_rootSavingContext] reset]; That fixed the missing defaultContext assertion.

#3 I added [[NSPersistentStoreCoordinator MR_defaultStoreCoordinator] removePersistentStore:[NSPersistentStore MR_defaultPersistentStore] error:&error]; immediately after reseting the NSManagedObjectContexts. Although, I'm not sure this is the right place to do this. As I get an EXE_BAD_ACCESS on "error" saving the second loop.

#7  0x00095232 in -[NSManagedObjectContext(MagicalRecord) contextWillSave:] at MagicalRecord/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalRecord.m:177

//////////////////
-[NSError release]: message sent to deallocated instance 0x8638a90
-[CFDictionary retain]: message sent to deallocated instance 0x8633ed0

#4 I was creating my own dispatch queue, and am calling [managedObjectContext MR_saveNestedContext] from within the queue, because this is the only way I can get through the database creation code at all. I would like to convert the entire operation to [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *managedObjectContext){} completion:^{} because it's much simpler, but I can't get it to work correctly. From what I understand, this should work, but doesn't:

//First, get a list of the databases to update, and send it off
[self shouldUpdateDatabases:updateList];

- (void)shouldUpdateDatabases:(NSArray *)updateList
{
    if ([updateList count] != 0) { //If there is a database to update
        //Get the name of the database folder, and documents directory
        NSString *directory = [updateList objectAtIndex:0];
        NSString *dirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        //remove the database we are about to update from the list
        NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:updateList];
         NSError *error = nil;
        [temp removeObjectAtIndex:0];

        //Setup store coordinator and default context
        [MagicalRecord setupCoreDataStackWithStoreNamed:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@/%@.sqlite", dirPath, directory, directory]]];

        [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *managedObjectContext) {

            //Add all entities to managedObjectContext.........

            //save, and reset stack for next loop
           NSLog(@"After:%i", [[Competition MR_findAllInContext:managedObjectContext] count]);
           } completion:^{
               [NSManagedObjectContext MR_resetDefaultContext];
               [[NSManagedObjectContext MR_rootSavingContext] reset];
               NSError *anotherError = nil;
               [[NSPersistentStoreCoordinator MR_defaultStoreCoordinator] removePersistentStore:[NSPersistentStore MR_defaultPersistentStore] error:&anotherError];
               NSLog(@"%@", error);
            [self shouldUpdateDatabases:temp];
        }];
    } 
}

How should this be done? If It cant be done with [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *managedObjectContext){} completion:^{}, I will post the other way I was trying to do this.

@Marxon13

I've figured out, that the only thing that is preventing the code from working is the EXC_BAD_ACCESS, preformed on an NSError.
The thread frames are as follows:

* thread #1: tid = 0x1c03, 0x01892caa libobjc.A.dylib`objc_exception_throw, stop reason = breakpoint 1.1
    frame #0: 0x01892caa libobjc.A.dylib`objc_exception_throw
    frame #1: 0x0018ac37 CoreData`-[NSPersistentStoreCoordinator(_NSInternalMethods) obtainPermanentIDsForObjects:error:] + 231
    frame #2: 0x0020dd86 CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 214
    frame #3: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #4: 0x0259b951 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 61
    frame #5: 0x0259be00 libdispatch.dylib`dispatch_barrier_sync_f + 62
    frame #6: 0x00196ff5 CoreData`_perform + 117
    frame #7: 0x0020eee8 CoreData`-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:] + 232
    frame #8: 0x0020deca CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 538
    frame #9: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #10: 0x0259a8d9 libdispatch.dylib`_dispatch_barrier_sync_f_slow_invoke + 93
    frame #11: 0x0259b509 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 353
    frame #12: 0x019da803 CoreFoundation`__CFRunLoopRun + 2003
    frame #13: 0x019d9d84 CoreFoundation`CFRunLoopRunSpecific + 212
    frame #14: 0x019d9c9b CoreFoundation`CFRunLoopRunInMode + 123
    frame #15: 0x025f57d8 GraphicsServices`GSEventRunModal + 190
    frame #16: 0x025f588a GraphicsServices`GSEventRun + 103
    frame #17: 0x009f5626 UIKit`UIApplicationMain + 1163
    frame #18: 0x00002b8d WhatsMyStageOn`main + 141 at main.m:16
* thread #1: tid = 0x1c03, 0x024caa44 libc++abi.dylib`__cxa_throw, stop reason = breakpoint 1.2
    frame #0: 0x024caa44 libc++abi.dylib`__cxa_throw
    frame #1: 0x01892de1 libobjc.A.dylib`objc_exception_throw + 311
    frame #2: 0x0018ac37 CoreData`-[NSPersistentStoreCoordinator(_NSInternalMethods) obtainPermanentIDsForObjects:error:] + 231
    frame #3: 0x0020dd86 CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 214
    frame #4: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #5: 0x0259b951 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 61
    frame #6: 0x0259be00 libdispatch.dylib`dispatch_barrier_sync_f + 62
    frame #7: 0x00196ff5 CoreData`_perform + 117
    frame #8: 0x0020eee8 CoreData`-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:] + 232
    frame #9: 0x0020deca CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 538
    frame #10: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #11: 0x0259a8d9 libdispatch.dylib`_dispatch_barrier_sync_f_slow_invoke + 93
    frame #12: 0x0259b509 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 353
    frame #13: 0x019da803 CoreFoundation`__CFRunLoopRun + 2003
    frame #14: 0x019d9d84 CoreFoundation`CFRunLoopRunSpecific + 212
    frame #15: 0x019d9c9b CoreFoundation`CFRunLoopRunInMode + 123
    frame #16: 0x025f57d8 GraphicsServices`GSEventRunModal + 190
    frame #17: 0x025f588a GraphicsServices`GSEventRun + 103
    frame #18: 0x009f5626 UIKit`UIApplicationMain + 1163
    frame #19: 0x00002b8d WhatsMyStageOn`main + 141 at main.m:16

And looking at the thread in the debug navigator:

#13 0x018a5d30 in objc_retain ()

#14 0x0009a2c0 in +[MagicalRecord(ErrorHandling) defaultErrorHandler:] at MagicalRecord/MagicalRecord/Core/MagicalRecord+ErrorHandling.m:26

#15 0x0009abd1 in +[MagicalRecord(ErrorHandling) handleErrors:] at MagicalRecord/MagicalRecord/Core/MagicalRecord+ErrorHandling.m:68

#16 0x00095219 in -[NSManagedObjectContext(MagicalRecord) contextWillSave:] at MagicalRecord/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalRecord.m:178

#17 0x013b7a29 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()

#21 0x001731c5 in -[NSManagedObjectContext save:] ()

#22 0x000959d8 in __65-[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:]_block_invoke_0 at MagicalRecord/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m:38

#23 0x00196d03 in developerSubmittedBlockToNSManagedObjectContextPerform ()

#24 0x00196c2f in -[NSManagedObjectContext performBlockAndWait:] ()

#25 0x00095532 in -[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:] at MagicalRecord/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m:37

#26 0x00095d44 in __85-[NSManagedObjectContext(MagicalSaves) MR_saveNestedContextsErrorHandler:completion:]_block_invoke_0 at MagicalRecord/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m:74

#27 0x0020edc3 in developerSubmittedBlockToNSManagedObjectContextPerform_privateasync ()

I'm trying to investigate further and find a fix, which I will post here if I can find one.

@Marxon13

Ok, the line that is causing the crash is line 177 on MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalRecord.m
in the method: - (void)contextWillSave:(NSNotification *)notification, specifically [context obtainPermanentIDsForObjects:insertedObjects error:&error];, where the NSError *error is being overreleased.

What's odd is that this is happening on the second run through of the code, and not the first.

@blackgold9
Collaborator

So, it looks like it's an arc issue, and I'm not sure on this, but since you have a repro can you try changing that contextWillSave method body to the following gist and letting me know if it helps?

https://gist.github.com/3856657
@Marxon13

Doesn't help. It now crashes on __autoreleasing NSError *error = nil; during the second loop of my code.

-[NSError release]: message sent to deallocated instance 0x13b5b830

And the frames:

* thread #1: tid = 0x1c03, 0x01892caa libobjc.A.dylib`objc_exception_throw, stop reason = breakpoint 3.1
    frame #0: 0x01892caa libobjc.A.dylib`objc_exception_throw
    frame #1: 0x0018ac37 CoreData`-[NSPersistentStoreCoordinator(_NSInternalMethods) obtainPermanentIDsForObjects:error:] + 231
    frame #2: 0x0020dd86 CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 214
    frame #3: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #4: 0x0259b951 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 61
    frame #5: 0x0259be00 libdispatch.dylib`dispatch_barrier_sync_f + 62
    frame #6: 0x00196ff5 CoreData`_perform + 117
    frame #7: 0x0020eee8 CoreData`-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:] + 232
    frame #8: 0x0020deca CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 538
    frame #9: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #10: 0x0259a8d9 libdispatch.dylib`_dispatch_barrier_sync_f_slow_invoke + 93
    frame #11: 0x0259b509 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 353
    frame #12: 0x019da803 CoreFoundation`__CFRunLoopRun + 2003
    frame #13: 0x019d9d84 CoreFoundation`CFRunLoopRunSpecific + 212
    frame #14: 0x019d9c9b CoreFoundation`CFRunLoopRunInMode + 123
    frame #15: 0x025f57d8 GraphicsServices`GSEventRunModal + 190
    frame #16: 0x025f588a GraphicsServices`GSEventRun + 103
    frame #17: 0x009f5626 UIKit`UIApplicationMain + 1163
    frame #18: 0x00002b5d WhatsMyStageOn`main + 141 at main.m:16
* thread #1: tid = 0x1c03, 0x024caa44 libc++abi.dylib`__cxa_throw, stop reason = breakpoint 3.2
    frame #0: 0x024caa44 libc++abi.dylib`__cxa_throw
    frame #1: 0x01892de1 libobjc.A.dylib`objc_exception_throw + 311
    frame #2: 0x0018ac37 CoreData`-[NSPersistentStoreCoordinator(_NSInternalMethods) obtainPermanentIDsForObjects:error:] + 231
    frame #3: 0x0020dd86 CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 214
    frame #4: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #5: 0x0259b951 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 61
    frame #6: 0x0259be00 libdispatch.dylib`dispatch_barrier_sync_f + 62
    frame #7: 0x00196ff5 CoreData`_perform + 117
    frame #8: 0x0020eee8 CoreData`-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:] + 232
    frame #9: 0x0020deca CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 538
    frame #10: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #11: 0x0259a8d9 libdispatch.dylib`_dispatch_barrier_sync_f_slow_invoke + 93
    frame #12: 0x0259b509 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 353
    frame #13: 0x019da803 CoreFoundation`__CFRunLoopRun + 2003
    frame #14: 0x019d9d84 CoreFoundation`CFRunLoopRunSpecific + 212
    frame #15: 0x019d9c9b CoreFoundation`CFRunLoopRunInMode + 123
    frame #16: 0x025f57d8 GraphicsServices`GSEventRunModal + 190
    frame #17: 0x025f588a GraphicsServices`GSEventRun + 103
    frame #18: 0x009f5626 UIKit`UIApplicationMain + 1163
    frame #19: 0x00002b5d WhatsMyStageOn`main + 141 at main.m:16
@blackgold9
Collaborator

Can you try the latest commit and let me know if that helps?

@Marxon13

It still fails in relatively the same location.
BOOL success = [context obtainPermanentIDsForObjects:insertedObjects error:&error]; Line 187 in NSManagedObjectContext+MagicalRecord.m. More specifically, in the method that this line calls.

#6  0x0018aa90 in -[NSManagedObjectContext obtainPermanentIDsForObjects:error:] ()
#7  0x000951c2 in -[NSManagedObjectContext(MagicalRecord) contextWillSave:] at MagicalRecord/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalRecord.m:187
#8  0x013b7a29 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()

Frames:

 thread #1: tid = 0x1c03, 0x01892caa libobjc.A.dylib`objc_exception_throw, stop reason = breakpoint 3.1
    frame #0: 0x01892caa libobjc.A.dylib`objc_exception_throw
    frame #1: 0x0018ac37 CoreData`-[NSPersistentStoreCoordinator(_NSInternalMethods) obtainPermanentIDsForObjects:error:] + 231
    frame #2: 0x0020dd86 CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 214
    frame #3: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #4: 0x0259b951 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 61
    frame #5: 0x0259be00 libdispatch.dylib`dispatch_barrier_sync_f + 62
    frame #6: 0x00196ff5 CoreData`_perform + 117
    frame #7: 0x0020eee8 CoreData`-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:] + 232
    frame #8: 0x0020deca CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 538
    frame #9: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #10: 0x0259a8d9 libdispatch.dylib`_dispatch_barrier_sync_f_slow_invoke + 93
    frame #11: 0x0259b509 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 353
    frame #12: 0x019da803 CoreFoundation`__CFRunLoopRun + 2003
    frame #13: 0x019d9d84 CoreFoundation`CFRunLoopRunSpecific + 212
    frame #14: 0x019d9c9b CoreFoundation`CFRunLoopRunInMode + 123
    frame #15: 0x025f57d8 GraphicsServices`GSEventRunModal + 190
    frame #16: 0x025f588a GraphicsServices`GSEventRun + 103
    frame #17: 0x009f5626 UIKit`UIApplicationMain + 1163
    frame #18: 0x00002aad WhatsMyStageOn`main + 141 at main.m:16
    frame #19: 0x000029d5 WhatsMyStageOn`start + 53
* thread #1: tid = 0x1c03, 0x024caa44 libc++abi.dylib`__cxa_throw, stop reason = breakpoint 3.2
    frame #0: 0x024caa44 libc++abi.dylib`__cxa_throw
    frame #1: 0x01892de1 libobjc.A.dylib`objc_exception_throw + 311
    frame #2: 0x0018ac37 CoreData`-[NSPersistentStoreCoordinator(_NSInternalMethods) obtainPermanentIDsForObjects:error:] + 231
    frame #3: 0x0020dd86 CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 214
    frame #4: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #5: 0x0259b951 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 61
    frame #6: 0x0259be00 libdispatch.dylib`dispatch_barrier_sync_f + 62
    frame #7: 0x00196ff5 CoreData`_perform + 117
    frame #8: 0x0020eee8 CoreData`-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:] + 232
    frame #9: 0x0020deca CoreData`__-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1 + 538
    frame #10: 0x00197051 CoreData`internalBlockToNSManagedObjectContextPerform + 17
    frame #11: 0x0259a8d9 libdispatch.dylib`_dispatch_barrier_sync_f_slow_invoke + 93
    frame #12: 0x0259b509 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 353
    frame #13: 0x019da803 CoreFoundation`__CFRunLoopRun + 2003
    frame #14: 0x019d9d84 CoreFoundation`CFRunLoopRunSpecific + 212
    frame #15: 0x019d9c9b CoreFoundation`CFRunLoopRunInMode + 123
    frame #16: 0x025f57d8 GraphicsServices`GSEventRunModal + 190
    frame #17: 0x025f588a GraphicsServices`GSEventRun + 103
    frame #18: 0x009f5626 UIKit`UIApplicationMain + 1163
    frame #19: 0x00002aad WhatsMyStageOn`main + 141 at main.m:16
    frame #20: 0x000029d5 WhatsMyStageOn`start + 53

Exception:

-[NSError release]: message sent to deallocated instance 0x13ec7f50
@Marxon13

I recently learned how to use instruments, and decided to give this another look. I figured out how to actually look at the history of the NSError that is being overreleased. Turns out Graphic Services is overreleasing the object. My question is what does Graphic Services have to do with this NSError? We're not dealing with graphics right? I wish I could give more, but a lot of this is still over my head. If you could point me in the right direction, I could continue looking for solutions.

#   Address Category    Event Type  RefCt   Timestamp   Size    Responsible Library Responsible Caller
0   0x1462c010  NSError Malloc  1   00:18.373.647   32  Foundation  +[NSError errorWithDomain:code:userInfo:]
1   0x1462c010  NSError Autorelease     00:18.373.656   0   Foundation  +[NSError errorWithDomain:code:userInfo:]
2   0x1462c010  NSError Autorelease     00:18.373.666   0   CoreData    __-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1
3   0x1462c010  NSError Retain  2   00:18.373.669   0   CoreData    __-[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]_block_invoke_1
4   0x1462c010  NSError Autorelease     00:18.373.670   0   CoreData    -[NSManagedObjectContext(_NestedContextSupport) _parentObtainPermanentIDsForObjects:error:]
5   0x1462c010  NSError Release 1   00:18.373.675   0   GraphicsServices    GSEventRunModal
6   0x1462c010  NSError Release 0   00:18.373.676   0   GraphicsServices    GSEventRunModal
7   0x1462c010  NSError Zombie  -1  00:18.373.698   0   GraphicsServices    GSEventRunModal
8   0x1462c010  NSError Zombie  -1  00:18.373.740   0   WhatsMyStageOn  +[MagicalRecord(ErrorHandling) handleErrors:]
@blackgold9
Collaborator

I have no idea what that could be. We're not using graphics services for anything.

@paulshapiro

I'm getting this exact progression of issues as well when I try to blow away my entire core data stack.

I'm doing it like this: https://gist.github.com/paulshapiro/8261c7d82590b3fc5786

Before I do this, I fire a notification that tells anyone with a context or managed object strong reference to release them. After all of this I fire another notification that lets them know to rebuild them.

Can't figure out what's going on here... Your insights and guidance would be highly appreciated.

@jogu

We're getting this issue too, but oddly can only reliably reproduce it on an iphone 3GS.

http://openradar.appspot.com/11478919 looks like it may be related.

Can anyone explain to me the need for the obtainPermanentIDsForObjects call here? What bad effects would happen if we didn't call it?

@jogu

Actually I'm not sure http://openradar.appspot.com/11478919 is really related, there seems to be a claim that bug was fixed in an iOS 6 beta, and it's iOS 6 we're seeing crash.

@jogu

btw, in our case, the NSError that's been overreleased (the overreleasing looks like it may be an iOS bug), we get this output prior to the crash on the device that has the problem:

+MagicalRecord(ErrorHandling) defaultErrorHandler: Error: Can't resolve how to assign objects to stores; Coordinator does not have any stores
+MagicalRecord(ErrorHandling) defaultErrorHandler: Error Message: The operation couldn’t be completed. (Cocoa error 134020.)
+MagicalRecord(ErrorHandling) defaultErrorHandler: Error Domain: NSCocoaErrorDomain
+MagicalRecord(ErrorHandling) defaultErrorHandler: Recovery Suggestion: (null)

So it seems like something went wrong in the initial store setup, though there's no logging from magical record to suggest any errors occurred whilst setting up the store - I plan to add some debugging to see what's happening there. Unfortunately I don't have physical access to the device the problem happens on, making debugging slow :(

@casademora
Owner
@jogu

The code we have is really simple, the problem seems to not be related to the code - essentially:

[MagicalRecord setupCoreDataStackWithStoreNamed:@"MyDatabase.sqlite"];
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
Claims *claim = [Claims MR_createInContext:localContext];
[localContext MR_saveToPersistentStoreAndWait];

We've now tracked down everything and I believe I fully understand this.

What was happening - somehow (despite being assured this bug happens after a clean install) one of our adhoc users had not done a clean install, and had an incompatible database from an old version - ie. addPersistentStoreWithType was failing, and returning a nil store and an error ("reason=The model used to open the store is incompatible with the one used to create the store").

MR_addSqliteStoreNamed: [I'm looking at the 2.2 release] does not pass this error to [MagicalRecord handleErrors] [as shouldDeleteStoreOnModelMismatch is NO]. (This may be a bug in MR - I think it should pass the error to the error handler in this case? Failing to create the store is probably worthy of an MRLog too!)

Then we call save, which results in MR_contextWillSave calling obtainPermanentIDsForObjects - this fails, "Error: Can't resolve how to assign objects to stores; Coordinator does not have any stores" (which is passed to the error handler).

It appears that the NSError returned by obtainPermanentIDsForObjects (or possibly another NSError) is overreleased, resulting in a crash when [NSManagedObjectContext save:] drains it's auto release pool. I believe this is a bug in iOS (we're seeing this on iOS 6.1.3).

@casademora
Owner
@jogu

Thanks casademora - we'll be putting together a patch for MR, give us a few days :) I'm going to try and get this tested on iOS 7 and reported to Apple if the NSError over-release still seems to be there too.

@jogu

@casademora There's a fix in #526 - if we made any mistakes when raising it please let us know

@tonyarnold tonyarnold closed this issue from a commit
@rhuariglen rhuariglen Report an error if the persistent store fails to initialise when `sho…
…uldDeleteStoreOnModelMismatch` is `NO`. Fixes #270.
a33ba77
@tonyarnold tonyarnold closed this in a33ba77
@mikegottlieb

Hey Guys. Google just turned up this thread because I was investigating the same NSError over-release problem mentioned above.

I can fix the problem if the error is a failure to initialize the store, but what if save fails for a different error? Won't this result in the same problem with over-releasing the NSError?

Also, has anyone confirmed that this is actually a bug in iOS? The Instruments trace suggests that, but above it looks like Apple claims to have fixed this already. I'm still seeing this in iOS 7.0.4.

@jogu

@mikeplaced Yes, I suspect it might, but it's hard to know for sure, it might only be one specific error path that causes the over release.

I never reported this to Apple as I didn't get time to retest it etc; if you still see this in 7.0.4 it's worth reporting it to them - possibly worth trying on 7.1 beta first though.

@adamwaite

@mikeplaced I'm receiving this now too. Not sure what's causing it. I'm sure more people will have reported it due to the size of MagicalRecord so I must be doing something? Did you ever figure out the steps to reproduce?

@adamwaite

This happens on the 64bit iOS simulator but not the standard 32bit. It's over-releasing the NSError inside:

BOOL success = [context obtainPermanentIDsForObjects:[insertedObjects allObjects] error:&error];

Downloading 7.1beta now, will let you know.

@mikegottlieb

@adamwaite so I had a few scenarios causing this and this is how I fixed them:

  1. Data protection API prevents accessing the store after phone reboot - Before setting up MagicalRecord I do this
   while(![[UIApplication sharedApplication] isProtectedDataAvailable]) {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5f]];
    }

This is because my app really needs database access to be useful. If data isn't available the OS will kill me for not completing applicationDidFinishLaunchingWithOptions in time.

2. The data store is corrupted - The best thing to do here is to delete the store and start over. Here is a good way to detect a corrupted store using the sqlite library directly

    #import <sqlite3.h>

    sqlite3 *dbConnection;
    if (sqlite3_open([[url absoluteString] UTF8String], &dbConnection) != SQLITE_OK) {
        NSLog(@"[SQLITE] Unable to open database!");
    }
    sqlite3_stmt *statement = nil;
    sqlite3_prepare_v2(dbConnection, "PRAGMA quick_check;", -1, &statement, NULL);
    NSString *result = nil;
    while (sqlite3_step(statement) == SQLITE_ROW) {
        for (int i=0; i<sqlite3_column_count(statement); i++) {
            int colType = sqlite3_column_type(statement, i);
            if (colType == SQLITE_TEXT) {
                const unsigned char *col = sqlite3_column_text(statement, i);
                result = [NSString stringWithFormat:@"%s", col];
            } else {
                NSLog(@"[SQLITE] UNKNOWN DATATYPE");
            }
        }
    }
    sqlite3_close(dbConnection);

This runs a sqlite PRAGMA query to perform an integrity check. I use quick_check, but you could also use integrity_check if you are willing to wait the extra time. You can tell things are good using [result isEqualToString:@"ok"]

@adamwaite

Thanks for the help

@gianlo86

-(void)initializePersistentStore{

NSString *nameDB=@"XXXXXXX.sqlite";

[MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:nameDB];


if ([[[NSPersistentStoreCoordinator MR_defaultStoreCoordinator] persistentStores] count] == 0){
    [MagicalRecord cleanUp];

    // delete database file
    NSError *error;
    NSURL *fileURL = [NSPersistentStore MR_urlForStoreName:nameDB];
    [[NSFileManager defaultManager] removeItemAtURL:fileURL error:&error];
    if(error) {
        // Hanldle error
    }

    // reset setup.
    [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:nameDB];
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.