I'm getting exceptions thrown during my unit tests, on a Core Data thread with this message:
CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'
*** First throw call stack:
(
0 CoreFoundation 0x00683a14 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x02334e02 objc_exception_throw + 50
2 CoreFoundation 0x0068393d +[NSException raise:format:] + 141
3 CoreFoundation 0x005595b9 -[__NSCFSet addObject:] + 185
4 CoreData 0x001d47c0 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processPendingInsertions:withDeletions:withUpdates:] + 560
5 CoreData 0x001cee8a -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2410
6 CoreData 0x001ce506 -[NSManagedObjectContext processPendingChanges] + 54
7 CoreData 0x001f359b developerSubmittedBlockToNSManagedObjectContextPerform + 443
I'm trying to determine what's causing it, but since it's occurring on an NSManagedObjectContext
queue, the thread has no stack trace with any of my own code.
I set symbolic breakpoints on -[__NSCFSet addObject:]
and -[NSManagedObjectContext processPendingChanges]
, but wasn't able to see any state while stopped there, helping me determine which objects are causing issues.
The next step that occurred to me was to try swizzling -[__NSCFSet addObject:]
to add my own implementation, so I could stop only when the argument is nil. Hopefully the set isn't empty, and I could get more information by seeing its contents before inserting nil. I ran into difficulties swizzling it, though, since it's a private class.
Using an approach above, or one I hadn't considered, how can I get more information on what's causing the exception?
Thanks to @bteapot for suggesting I add the -com.apple.CoreData.ConcurrencyDebug 1
argument to my scheme. I got more information on how this works from Ole Begemann's excellent Core Data Concurrency Debugging article.
Adding this flag causes an exception to be thrown as soon as your code calls into your NSManagedObjectContext
from an incorrect thread. This works great in Xcode, but be advised that in an Xcode Bot, this causes tests to fail with this unhelpful message:
Lost connection to test manager service