Core Data crash NSInternalInconsistencyException 'statement is still active'
Asked Answered
C

2

22

I have two managed object contexts that share the same persistent store coordinator:

  • One with NSMainQueueConcurrencyType for the main thread and
  • One that's NSPrivateQueueConcurrencyType for doing background processing.

All data parsing work happens in performBlock calls against the private queue and are merged in via NSManagedObjectContextDidSaveNotification for UI updates on the main thread.

I have Core Data Multithreading assertions enabled, and they never trigger when the crash occurs.

I will occasionally get a crash that says statement is still active when I push in a new view that has a NSFetchedResultsController while the background context is working. The crash will either trigger on the fetch for the fetched results controller or within the code that is storing data. When it crashes in the data parsing section it always fails at a to-many relationship.

These crashes are 100% iOS 8 so far and I've never seen them on 7.

My question is this: assuming that I am not violating thread confinement (which the assertion should yell loudly about, and hasn't...) is there anything else obvious that I could be doing that would cause the main thread context to bomb out while the background thread is in the process of doing work on the persistent store?

Here's what Crashlytics says:

Thread : Fatal Exception: NSInternalInconsistencyException
0  CoreFoundation                 0x00000001871e659c __exceptionPreprocess + 132
1  libobjc.A.dylib                0x00000001978f00e4 objc_exception_throw + 60
2  CoreData                       0x0000000186e97c6c -[NSSQLiteStatement cachedSQLiteStatement]
3  CoreData                       0x0000000186e9739c -[NSSQLiteConnection prepareSQLStatement:] + 76
4  CoreData                       0x0000000186eb3810 -[NSSQLChannel selectRowsWithCachedStatement:] + 76
5  CoreData                       0x0000000186f9e7a4 newFetchedRowsForFetchPlan_MT + 1100
6  CoreData                       0x0000000186ecf948 -[NSSQLCore newFetchedPKsForSourceID:andRelationship:] + 2120
7  CoreData                       0x0000000186ecea24 -[NSSQLCore newValueForRelationship:forObjectWithID:withContext:error:] + 616
8  CoreData                       0x0000000186f67480 __110-[NSPersistentStoreCoordinator(_NSInternalMethods) newValueForRelationship:forObjectWithID:withContext:error:]_block_invoke + 80
9  CoreData                       0x0000000186f6d654 gutsOfBlockToNSPersistentStoreCoordinatorPerform + 180
10 CoreData                       0x0000000186f60ccc _perform + 204
11 CoreData                       0x0000000186ece730 -[NSPersistentStoreCoordinator(_NSInternalMethods) newValueForRelationship:forObjectWithID:withContext:error:] + 160
12 CoreData                       0x0000000186ece4d8 -[NSFaultHandler retainedFulfillAggregateFaultForObject:andRelationship:withContext:] + 716
13 CoreData                       0x0000000186ef15ec -[_NSFaultingMutableSet willReadWithContents:] + 444
14 CoreData                       0x0000000186ed146c -[_NSFaultingMutableSet count] + 32
15 CoreData                       0x0000000186ecd234 -[NSManagedObject(_NSInternalMethods) _didChangeValue:forRelationship:named:withInverse:] + 440
16 Foundation                     0x0000000187fe1a14 NSKeyValueNotifyObserver + 340
17 Foundation                     0x0000000187fe1534 NSKeyValueDidChange + 460
18 Foundation                     0x0000000187fcaac4 -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] + 116
19 CoreData                       0x0000000186ec4e90 _PF_ManagedObject_DidChangeValueForKeyIndex + 140
20 CoreData                       0x0000000186ec3248 _sharedIMPL_setvfk_core + 284
21 My App                     0x00000001000f0b00 -[LocationAdapter processBuildingList:context:completion:] (LocationAdapter.m:134)
Compulsion answered 19/2, 2015 at 16:46 Comment(5)
Are you using completion blocks to respond to the background context completing some action? If so look at this question.Yttriferous
I do have a completion block in there that ultimately triggers some UI work on the main thread, but it is only getting called once.Compulsion
Is this happening when testing on a simulator or is it on a device? And did this start happening after you updated your CoreData model?Shelbyshelden
just to check, try to add @syncronize around the lines you are saving/reading from the store and see if the crash stops. If it stops you have multiple threads trying to access the store.Diaphaneity
Did you finally figure this out?Codpiece
C
1

I ended up changing around how I created the core data stack and this went away. Moving to a persistent store context, a child UI context, and a grandchild background context and persisting up the chain appropriately made this all better. I'm still not 100% sure why the original setup did not work with 8.

Compulsion answered 21/1, 2016 at 19:9 Comment(0)
S
0

You can use copy of nsmanaged object context as a new instance of nsmanagedobject context. For each managed object context you should use like this where you want to save inconsistency in multithreading

[backgroundMOC performBlockAndWait:^{
    // read/write operation
    [backgroundMOC saveContextWithMOC:backgroundMOC];
}];

// Main Thread MOC

[mainMOC performBlockAndWait:^{
    // read/write operation
    [backgroundMOC saveContextWithMOC:backgroundMOC];
}];
Scotch answered 21/12, 2015 at 14:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.