Since upgrading to XCode 6.3 and iOS 8.3 I'm getting a new error in my app, when merging NSManagedObjectContexts (MOCs) from the background to the main thread MOC.
My architecture has a primary MOC on the main thread, and creates several background MOCs on other threads that are temporary and just used to sync new server data. When those background MOCs save, I listen for the notification NSManagedObjectContextDidSaveNotification on the main thread and call mergeChangesFromContextDidSaveNotification on the main MOC.
This is per the documentation on threading with Core Data (see Core Data Concurrency).
This used to work fine, but as of this update started crashing with this error, which I can't trace back to a specific line of my code:
illegally invoked -perform* on dying NSManagedObjectContext at:
(
0 CoreData 0x28a2f273 <redacted> + 118
1 CoreData 0x28a32f09 <redacted> + 192
2 CoreFoundation 0x28c64e09 <redacted> + 12
3 CoreFoundation 0x28bbf515 _CFXNotificationPost + 1784
4 Foundation 0x29920749 <redacted> + 72
5 Foundation 0x2992522f <redacted> + 30
6 Foundation 0x29986a93 <redacted> + 98
7 Foundation 0x299867f7 <redacted> + 82
8 Foundation 0x299dfbd5 <redacted> + 408
9 CoreFoundation 0x28c72fed <redacted> + 20
10 CoreFoundation 0x28c706ab <redacted> + 278
11 CoreFoundation 0x28c709ff <redacted> + 734
12 CoreFoundation 0x28bbd201 CFRunLoopRunSpecific + 476
13 CoreFoundation 0x28bbd013 CFRunLoopRunInMode + 106
14 GraphicsServices 0x30359201 GSEventRunModal + 136
15 UIKit 0x2c361a59 UIApplicationMain + 1440
16 MyAppName 0x000c95a7 main + 170
17 libdyld.dylib 0x376c1aaf <redacted> + 2
)
I've turned zombies on in XCode, looking for deallocated contexts, but haven't found any. The main-thread listener that calls merge looks like this:
- (void)coreDataDidSaveNotification:(NSNotification *)notification {
NSManagedObjectContext *savedContext = (NSManagedObjectContext *)notification.object;
if (savedContext != self.mainManagedObjectContext) {
__weak typeof(self) weakSelf = self;
[self.dispatch dispatchOnMainThread:^{
NSLog(@"before merge");
[weakSelf.mainManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];
NSLog(@"after merge");
}];
}
}
The log message "after merge" gets called before the crash happens, which is extra confusing. I've checked retainCount on the background context in the notification and it's always greater than zero when the merge is called, so it's not getting released at that point.
Any idea what is happening?