I use Core Data in my iOS project.
I am using multiple contexts in the following way. I have a persisent store context that operates on a private queue and stores changes to the persistent store.
I have a main queue context that is the child of persistent store context. All of the FRCs in my app use this context.
And finally, if I have to do some changes that I want to save in a batch, I create and use new NSManagedObjectContexts that are children of the main queue context.
So I have a chain:
DB < persistent store context < main queue context < any other child contexts
I have a singleton that retains both persistent store context and main queue context. This singleton also listens to NSManagedObjectContextObjectsDidChangeNotification notification on persistent store context and reacts to the notification like this:
-(void) persistentStoreContextDidChangeNotification:(NSNotification*)notification
{
if (notification.object == self.persistentStoreContext) {
[self.persistentStoreContext performBlockAndWait:^{
//on every change on persistentStoreContext, save those changes using background thread to real persistent store
NSError *error = nil;
[self.persistentStoreContext save:&error];
}];
}
}
So, when I call [mainQueueContext save], this is enough for all changes in mainQueueContext to be persisted in the filesystem.
Using Crashlytics, I am getting a lot of crash reports like this:
Fatal Exception: NSInternalInconsistencyException
Can't create externalDataReference interim file : 28
Thread : Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x0000000183f51e48 __exceptionPreprocess + 132
1 libobjc.A.dylib 0x000000019464c0e4 objc_exception_throw + 60
2 CoreData 0x0000000183c6e5b4 +[_PFRoutines writePFExternalReferenceDataToInterimFile:] + 960
3 CoreData 0x0000000183ceaa4c -[NSSQLCore writeExternalDataReferences] + 224
4 CoreData 0x0000000183c429fc -[NSSQLCore saveChanges:] + 596
5 CoreData 0x0000000183c0b078 -[NSSQLCore executeRequest:withContext:error:] + 720
6 CoreData 0x0000000183cd2254 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 4052
7 CoreData 0x0000000183cd9654 gutsOfBlockToNSPersistentStoreCoordinatorPerform + 180
8 libdispatch.dylib 0x0000000194c9136c _dispatch_client_callout + 16
9 libdispatch.dylib 0x0000000194c9a6e8 _dispatch_barrier_sync_f_invoke + 76
10 CoreData 0x0000000183ccccb4 _perform + 180
11 CoreData 0x0000000183c0ac34 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 300
12 CoreData 0x0000000183c31400 -[NSManagedObjectContext save:] + 1284
13 MyApp 0x00000001000d17e0 __58-[XEECDStack persistentStoreContextDidChangeNotification:]_block_invoke (XEECDStack.m:426)
14 CoreData 0x0000000183ca5270 developerSubmittedBlockToNSManagedObjectContextPerform + 200
15 CoreData 0x0000000183ca5474 -[NSManagedObjectContext performBlockAndWait:] + 232
16 MyApp 0x00000001000d1774 -[XEECDStack persistentStoreContextDidChangeNotification:] (XEECDStack.m:423)
17 CoreFoundation 0x0000000183ef81e0 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
18 CoreFoundation 0x0000000183e37370 _CFXNotificationPost + 2060
19 Foundation 0x0000000184d32cc0 -[NSNotificationCenter postNotificationName:object:userInfo:] + 72
20 CoreData 0x0000000183c33d14 -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] + 364
21 CoreData 0x0000000183c321bc -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2552
22 CoreData 0x0000000183cadba4 -[NSManagedObjectContext(_NestedContextSupport) _parentProcessSaveRequest:inContext:error:] + 1568
23 CoreData 0x0000000183cae684 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke + 600
24 CoreData 0x0000000183cb0398 internalBlockToNSManagedObjectContextPerform + 108
25 libdispatch.dylib 0x0000000194c9136c _dispatch_client_callout + 16
26 libdispatch.dylib 0x0000000194c9a6e8 _dispatch_barrier_sync_f_invoke + 76
27 CoreData 0x0000000183ca06cc _perform + 208
28 CoreData 0x0000000183cae354 -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] + 176
29 CoreData 0x0000000183c31400 -[NSManagedObjectContext save:] + 1284
30 MyApp 0x000000010012ea14 __78-[MyAppManager downloadMediaIfNeededForMyAppWithManagedObjectID:onCompletion:]_block_invoke (MyAppManager.m:415)
31 MyApp 0x00000001001ce06c __38-[FLNMyAppMediaDownloadOperation main]_block_invoke60 (FLNMyAppMediaDownloadOperation.m:84)
32 Foundation 0x0000000184e07508 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
33 Foundation 0x0000000184d58c94 -[NSBlockOperation main] + 96
34 Foundation 0x0000000184d4861c -[__NSOperationInternal _start:] + 636
35 Foundation 0x0000000184e0a26c __NSOQSchedule_f + 228
36 libdispatch.dylib 0x0000000194c9136c _dispatch_client_callout + 16
37 libdispatch.dylib 0x0000000194c95980 _dispatch_main_queue_callback_4CF + 932
38 CoreFoundation 0x0000000183f096a0 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
39 CoreFoundation 0x0000000183f07748 __CFRunLoopRun + 1492
40 CoreFoundation 0x0000000183e351f4 CFRunLoopRunSpecific + 396
41 GraphicsServices 0x000000018cfcb5a4 GSEventRunModal + 168
42 UIKit 0x0000000188766784 UIApplicationMain + 1488
43 MyApp 0x0000000100119cc8 main (main.m:17)
44 libdyld.dylib 0x0000000194cbaa08 start + 4
So, in this specific crash, the line
30 MyApp 0x000000010012ea14 __78-[MyAppManager downloadMediaIfNeededForMyAppWithManagedObjectID:onCompletion:]_block_invoke (MyAppManager.m:415)
is calling [mainQueueContext save].
The same crash occurs in situations where the [mainQueueContext save] is called from different parts of the app.
I am trying to find out what are the possible reasons why I am seeing this exception. And I cannot find anything on Google when searching for "Can't create externalDataReference interim file"
EDIT
I have went through specific crash instances and looked at them one by one. Although the stack trace of every crash is fairly similar, it turns out that the exception differs a little bit between instances.
The differents 'versions' of this crash are:
Fatal Exception: NSInternalInconsistencyException
External data reference can't find underlying file.
,
Fatal Exception: NSInternalInconsistencyException
Missing bytes from file at path /private/var/mobile/Containers/Data/Application/E9D51467-7941-41B8-88EE-31A70A82BC40/tmp/.LINKS/BD171390-D95C-459E-96D6-462318016138/EDB75A4F-C8FD-4BC4-ABD1-BA408F3A7DC9_0x18038c80, expected 276428, got 4294967295
,
Fatal Exception: NSInvalidArgumentException
Unable to open file with path: /var/mobile/Containers/Data/Application/19E53BC4-7891-4B0C-9454-27C1A0DAB2A0/Documents/persistent-store/.Model_SUPPORT/_EXTERNAL_DATA/CA6BCE7D-0C74-41CF-8784-8EB1F66DFF4C (13)
,
Fatal Exception: NSInternalInconsistencyException
This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.
Also, I have discovered a pattern shared by almost all the crashes of this type.
The available disk space on the device is extremely low. On iPhone 4 and iPhone 5 devices the available disk space is 0%. And on iPhone 6, it's always 8%.
I suspect that the iPhone 6 reserves 8% of disk space "for special occasions".
I use a similar process in my app, with two contexts set during the construction of my core data stack and using:
NSPrivateQueueConcurrencyType,
NSMainQueueConcurrencyType.
To take a guess, the blocks may be conflicting with the operation of the notification, however that is a guess.
For my app I've modified the solution presented by Marcus Zarra in his book from The Pragmatic Bookshelf – "Core Data, 2nd Edition, Data Storage and Management for iOS, OS X, and iCloud" (Jan 2013).
For a more up to date and all encompassing solution that I have not yet implemented, read this article My Core Data Stack by Zarra.
My modified solution involves writing a custom save method built alongside (in the same class as) my core data stack, shown following, instead of using a NSManagedObjectContextObjectsDidChangeNotification. Note that the save method is called at appropriate points in code.
Maybe this is a suitable alternative?
Properties...
#property (nonatomic, strong) NSManagedObjectContext *mocPrivate;
#property (nonatomic, strong) NSManagedObjectContext *mocMain;
Custom save method...
- (void)saveContextAndWait:(BOOL)wait {
if ([self.mocMain hasChanges]) {
[self.mocMain performBlockAndWait:^{
NSError __autoreleasing *error;
BOOL success;
if (!(success = [self.mocMain save:&error]))
NSLog(#"%# - %# - CORE DATA - E~R~R~O~R saving managedObjectContext MAIN: %#, %#", NSStringFromClass(self.class), NSStringFromSelector(_cmd), error.localizedDescription, error.localizedFailureReason);
NSLog(#"%# - %# - CORE DATA - Success saving managedObjectContext MAIN?: %#", NSStringFromClass(self.class), NSStringFromSelector(_cmd), success ? #"YES_" : #"NO_");
}];
}
void (^savePrivate) (void) = ^{
NSError __autoreleasing *error;
BOOL success;
if (!(success = [self.mocPrivate save:&error]))
NSLog(#"%# - %# - CORE DATA - E~R~R~O~R saving managedObjectContext PRIVATE: %#, %#", NSStringFromClass(self.class), NSStringFromSelector(_cmd), error.localizedDescription, error.localizedFailureReason);
NSLog(#"%# - %# - CORE DATA - Success saving managedObjectContext PRIVATE?: %#", NSStringFromClass(self.class), NSStringFromSelector(_cmd), success ? #"YES_" : #"NO_");
};
if ([self.mocPrivate hasChanges]) {
if (wait) {
[self.mocPrivate performBlockAndWait:savePrivate];
} else {
[self.mocPrivate performBlock:savePrivate];
}
}
}
I have managed to reproduce this issue by filling up entire disk space on the device and then using the app, storing media in Core Data.
After some time using the app, a warning popup shows that the device is low on disk space. I dismiss the warning and continue to use the app.
After some additional time, the app crashes with the message:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Can't create externalDataReference interim file : 28'
Related
I am assuming it is ok to post beta iOS10 issues here, since it is an open beta. The apple forums don't come close to the help one gets on Stackoverflow.
Since the update to iOS10, our users are getting a constant crash when saving the managedObjectContext in CoreData.
This is something that has worked flawlessly since iOS 5.
It only happens on the 64 bit version of iOS10. The 32 bit version works fine.
Here is my simple save code snip:
[self.managedObjectContext performBlockAndWait:^{
NSError *error;
if (![self.managedObjectContext save:&error])
{
NSLog(#"\n\nerror in save 1 %#\n\n", error);
}
}];
[self.managedObjectContext performBlock:^{
NSError *error;
if (![_privateWriterContext save:&error])
{
NSLog(#"\n\nerror in save 2 %#\n\n", error);
}
}];
(Above NSLog reports nothing, as it works in simulator).
This only fails on a 64bit device. I cannot replicate on the simulator. I also cannot replicate in debug on a device due to issues with my only 64 bit device not connecting to Xcode correctly. So I am a bit stuck.
Below is a sample stack trace reported from a user:
Incident Identifier: 7A8DD23B-48A2-4ABF-88E7-67F1E6CDA8D5
CrashReporter Key: 5454e7c7b99a94cd75b6adfa8334bbdf10b859eb
Hardware Model: iPhone8,1
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Date/Time: 2016-07-20 22:23:00.1429 -0400
Launch Time: 2016-07-20 22:21:30.6058 -0400
OS Version: iPhone OS 10.0 (14A5309d)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000985e4beb8
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 libobjc.A.dylib 0x00000001850e6eb0 objc_msgSend + 16
1 CoreFoundation 0x0000000185a76740 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20 (CFNotificationCenter.c:650)
2 CoreFoundation 0x0000000185a75e44 _CFXRegistrationPost + 400 (CFNotificationCenter.c:164)
3 CoreFoundation 0x0000000185a75bc0 ___CFXNotificationPost_block_invoke + 60 (CFNotificationCenter.c:1031)
4 CoreFoundation 0x0000000185ae40cc -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1504 (CFXNotificationRegistrar.m:163)
5 CoreFoundation 0x00000001859b9484 _CFXNotificationPost + 376 (CFNotificationCenter.c:1028)
6 Foundation 0x000000018644e9dc -[NSNotificationCenter postNotificationName:object:userInfo:] + 68 (NSNotification.m:482)
7 CoreData 0x0000000187e1dbf4 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postContextDidSaveNotificationWithUserInfo:] + 880 (NSManagedObjectContext.m:7381)
8 CoreData 0x0000000187dabb4c -[NSManagedObjectContext(_NSInternalAdditions) _didSaveChanges] + 2156 (NSManagedObjectContext.m:5827)
9 CoreData 0x0000000187d98570 -[NSManagedObjectContext save:] + 3440 (NSManagedObjectContext.m:1532)
10 App 0x000000010008db34 __29-[RPSAppDelegate saveContext]_block_invoke227 + 52 (RPSAppDelegate.m:338)
11 CoreData 0x0000000187e17c68 developerSubmittedBlockToNSManagedObjectContextPerform + 168 (NSManagedObjectContext.m:3529)
12 libdispatch.dylib 0x0000000185525784 _dispatch_client_callout + 16 (object.m:455)
13 libdispatch.dylib 0x000000018552a330 _dispatch_main_queue_callback_4CF + 1000 (inline_internal.h:2421)
14 CoreFoundation 0x0000000185a8a0cc __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 (CFRunLoop.c:1793)
15 CoreFoundation 0x0000000185a87cb8 __CFRunLoopRun + 1660 (CFRunLoop.c:3004)
16 CoreFoundation 0x00000001859b78d8 CFRunLoopRunSpecific + 444 (CFRunLoop.c:3113)
17 GraphicsServices 0x00000001873be198 GSEventRunModal + 180 (GSEvent.c:2245)
18 UIKit 0x000000018b9617c8 -[UIApplication _run] + 664 (UIApplication.m:2651)
19 UIKit 0x000000018b95c534 UIApplicationMain + 208 (UIApplication.m:4088)
20 App 0x000000010008c138 main + 152 (main.m:27)
21 libdyld.dylib 0x00000001855585b8 start + 4
Thank you for any ideas.
You are saving _privateWriterContext in a block call of managedObjectContext. This is not allowed. The fact that it worked before is a "false positive".
Instead, you should always only use at the same context that creates the block.
I have an NSOrderedSet attached to a Core Data object that's passed into a UITableViewController. The managedObjectContext is alive and well in the UITableViewController and myNSOrderedSet displays properly my tableView. When I go to reorder myNSOrderedSet, the app crashes. I put a breakpoint in moveRowAtIndexPath to see what's going on and everything's fine up until I try to save it.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
// BREAKPOINT: "po self.routineToEdit.exercises" shows order is 0, 1, 2
NSMutableOrderedSet *orderedSet = [self.routineToEdit.exercises mutableCopy];
[orderedSet exchangeObjectAtIndex:fromIndexPath.row withObjectAtIndex:toIndexPath.row];
// BREAKPOINT: "po self.routineToEdit.exercises" shows order is 2, 1, 0
self.routineToEdit.exercises = orderedSet;
[self saveContext];
}
- (void)saveContext {
if (self.managedObjectContext != nil) {
NSError *error = nil;
if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
Rather than passing my object into MyUITableViewController, I'm tempted to use a fetchedResultsController to grab my object and display it on MyUITableViewController. Before I go that route, I'd like to see I can re-order an NSOrderedSet with the object that's passed in from AnotherUITableViewController.
Here's the console output from my crash:
2015-07-12 06:39:53.176 MyApp[26505:1105589] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString appendString:]: nil argument'
*** First throw call stack:
(
0 CoreFoundation 0x00000001060dec65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000105663bb7 objc_exception_throw + 45
2 CoreFoundation 0x00000001060deb9d +[NSException raise:format:] + 205
3 CoreFoundation 0x00000001060afabf mutateError + 159
4 CoreData 0x000000010591ec26 -[_NSSQLGenerator prepareMasterReorderStatementPart2ForRelationship:] + 118
5 CoreData 0x000000010598cfb8 -[NSSQLAdapter newCorrelationMasterReorderStatementPart2ForRelationship:] + 72
6 CoreData 0x00000001059a5671 -[NSSQLiteConnection writeCorrelationMasterReordersFromTracker:] + 817
7 CoreData 0x00000001059a5f81 -[NSSQLiteConnection writeCorrelationChangesFromTracker:] + 65
8 CoreData 0x0000000105997627 -[NSSQLCore writeChanges] + 1351
9 CoreData 0x00000001058d32c7 -[NSSQLCore saveChanges:] + 423
10 CoreData 0x00000001058a3e74 -[NSSQLCore executeRequest:withContext:error:] + 484
11 CoreData 0x000000010597ee3f __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 4335
12 CoreData 0x0000000105987c30 gutsOfBlockToNSPersistentStoreCoordinatorPerform + 192
13 libdispatch.dylib 0x0000000108890614 _dispatch_client_callout + 8
14 libdispatch.dylib 0x0000000108876002 _dispatch_barrier_sync_f_invoke + 365
15 CoreData 0x0000000105979245 _perform + 197
16 CoreData 0x00000001058a3a58 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 504
17 CoreData 0x00000001058cd52d -[NSManagedObjectContext save:] + 1213
18 MyApp 0x000000010511083e -[EditRoutineTableViewController saveContext] + 222
19 MyApp 0x0000000105110673 -[EditRoutineTableViewController tableView:moveRowAtIndexPath:toIndexPath:] + 371
20 UIKit 0x0000000106817822 -[UITableView _endReorderingForCell:wasCancelled:animated:] + 565
21 UIKit 0x000000010682b89d -[UIControl touchesEnded:withEvent:] + 462
22 UIKit 0x0000000106767958 -[UIWindow _sendTouchesForEvent:] + 735
23 UIKit 0x0000000106768282 -[UIWindow sendEvent:] + 682
24 UIKit 0x000000010672e541 -[UIApplication sendEvent:] + 246
25 UIKit 0x000000010673bcdc _UIApplicationHandleEventFromQueueEvent + 18265
26 UIKit 0x000000010671659c _UIApplicationHandleEventQueue + 2066
27 CoreFoundation 0x0000000106012431 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
28 CoreFoundation 0x00000001060082fd __CFRunLoopDoSources0 + 269
29 CoreFoundation 0x0000000106007934 __CFRunLoopRun + 868
30 CoreFoundation 0x0000000106007366 CFRunLoopRunSpecific + 470
31 GraphicsServices 0x000000010a12ba3e GSEventRunModal + 161
32 UIKit 0x00000001067198c0 UIApplicationMain + 1282
33 MyApp 0x000000010510a05f main + 111
34 libdyld.dylib 0x00000001088c4145 start + 1
Thank you for reading. I welcome your input.
I found this issue that's in the "same neighborhood" of the problem I'm encountering, however the order of my set is not static like the example given in the example.
Core Data ordering with a UITableView and NSOrderedSet
I think the fetch results controller does not give you any advantage here (mainly due to the sorting requirement which does not make sense here).
I would just use the ordered set (the to-many relationship of the object being edited) directly to inform your table view data source. And I would check that assigning the newly ordered ordered set back to the object is working as expected.
The StackOverflow consensus seems to be there's a bug with how NSOrderedSet relationships are handled by Core Data. I was able to manipulate the order of my NSOrderedSet using the information contained in Dmitry Makarenko's post on the accessors generated by Xcode:
Exception thrown in NSOrderedSet generated accessors
I also cleaned up (at least I think so) the code I used for moving rows in the UITableView:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
NSMutableOrderedSet *orderedSet = [self.routineToEdit mutableOrderedSetValueForKey:#"stretches"].mutableCopy;
// This is necessary, as exchangeObjectAtIndex:withObjectAtIndex doesn't work passing in indexPath.row
NSInteger fromIndex = fromIndexPath.row;
NSInteger toIndex = toIndexPath.row;
// Swap objects at indexes
[orderedSet exchangeObjectAtIndex:fromIndex withObjectAtIndex:toIndex];
NSLog(#"ending orderedSet = /n%#", orderedSet);
// Assign NSMutableOrderdSet to the object's NSOrderedSet
self.routineToEdit.stretches = orderedSet;
// Added performBlockAndWait so the save is complete before doing anything else
[self.persistentStoreCoordinator performBlockAndWait:^{
[self saveContext];
}];
}
Saving the object to the managedObjectContext right after the UITableView rows/NSObjects are swapped is critical--I discovered this when I saw not all my changes were being saved when I clicked a Done IBAction w/ the save method invoked there:
[self.persistentStoreCoordinator performBlockAndWait:^{
[self saveContext];
}];
...but the app still crashed.
Finally, I changed the relationship between BOTH entities to ordered and that did the trick:
crash on coredata ios8
For my purposes, this is sufficient. I tried each of these fixes independently and none of them worked on a stand-alone basis. At this point, my app works the way I want it to, so I'm going to leave it alone for now.
You are already halfway there by calling mutableOrderedSetValueForKey:, don't call mutableCopy on it! Also, do not reassign this mutable ordered set back to exercises. just save your context, call refreshObject:mergeChanges: on the context, and exercises should reflect your changes.
Currently I'm working with MagicalRecord v2.3.0-beta.3 commit:d18e74fe435359238b9593c03e41c1ee0baa0b78 framework. I'm getting 1 a crash log (from Crashlytics) on iPhone 5 all the time. App is still in development. The crash log looks like below:
Thread : Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x38eee626 objc_msgSend + 5
1 Foundation 0x2f06d02d -[NSError dealloc] + 60
2 libobjc.A.dylib 0x38ef3b6b objc_object::sidetable_release(bool) + 174
3 libobjc.A.dylib 0x38ef40d3 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 358
4 CoreFoundation 0x2e67d481 _CFAutoreleasePoolPop + 16
5 Foundation 0x2f0778e3 -[NSAutoreleasePool drain] + 122
6 CoreData 0x2e4bdfbf -[NSManagedObjectContext save:] + 942
7 MyApp 0x00162f9f __70-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:]_block_invoke15 (NSManagedObjectContext+MagicalSaves.m:82) // here app crashes
8 CoreData 0x2e5219cd developerSubmittedBlockToNSManagedObjectContextPerform + 88
9 CoreData 0x2e521b13 -[NSManagedObjectContext performBlockAndWait:] + 114
10 MyApp 0x00162e51 -[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:] (NSManagedObjectContext+MagicalSaves.m:116)
11 MyApp 0x000a2b0d -[SPNCoreDataHandler parseAndSaveDictionaryReturnOperationArray:withSaving:] (SPNCoreDataHandler.m:70)
12 MyApp 0x00078f21 __102-[SPNApiHandler getAllDataWithDownloadingSuccessBlock:savingSuccessBlock:downloadStatus:failureBlock:]_block_invoke (SPNApiHandler.m:69)
13 MyApp 0x000795b9 __66-[SPNApiHandler sendGetRequestWithPath:successBlock:failureBlock:]_block_invoke (SPNApiHandler.m:174)
14 libdispatch.dylib 0x393cdd53 _dispatch_call_block_and_release + 10
15 libdispatch.dylib 0x393cdd3f _dispatch_client_callout + 22
16 libdispatch.dylib 0x393d06c3 _dispatch_main_queue_callback_4CF + 278
17 CoreFoundation 0x2e714641 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
18 CoreFoundation 0x2e712f0d __CFRunLoopRun + 1308
19 CoreFoundation 0x2e67d729 CFRunLoopRunSpecific + 524
20 CoreFoundation 0x2e67d50b CFRunLoopRunInMode + 106
21 GraphicsServices 0x335ec6d3 GSEventRunModal + 138
22 UIKit 0x30fde871 UIApplicationMain + 1136
23 MyApp 0x0009c347 main (main.m:16)
And here's code which I wrote:
NOTE: I removed some parts of this method for sake of readability (that's why method returns void instead of NSArray).
- (NSArray *)parseAndSaveDictionaryReturnOperationArray:(NSDictionary *)dictionary withSaving:(BOOL)saveSynchrounously {
[self truncateAll]; //method which removes all entries in coreData
/* methods below creates entities from array given in dictionary
using [NSManagedObject MR_createEntity] method
e.g. Contact *contact = [Contact MR_createEntity]; */
[self saveContacts:dictionary[#"contact"]];
[self savePeople:dictionary[#"person"]];
[self saveBuildings:dictionary[#"place"]];
[self saveSessions:dictionary[#"session"]];
[self saveLectures:dictionary[#"program"]];
[self savePartners:dictionary[#"partners"]];
[self saveSponsors:dictionary[#"sponsors"]];
[self saveExhibitorsPlans:dictionary[#"exhibitorplan"]];
[self saveMeetingPlans:dictionary[#"meetingplan"]];
[self saveOrganizationalInformation:dictionary[#"info"]];
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
//continue executing method...
}
I tried also to use [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreWithCompletion:] method but it crashes too.
In other Stackoverflow question someone suggested, that crash can be caused by deleting, creating and saving to many entities at once. In my case it's around 200 deleted entities + 200 new ones. Can it cause crash?
On other devices (iPhone 4s, iPhone 5s, iPad 2, iPad4, iPad mini) it works fine. Any ideas what I'm doing wrong?
Finally I found out what was going on. Tester didn't delete and install an app as I told. Crash appears because DB schema changed. Maybe I should start to think about DB versioning during development to avoid those kind of issues.
Thanks anyone for answers.
I apologize in advance that this probably won't end up contributing much to the general knowledge base here, but I'm looking for help diagnosing what's likely a configuration oversight that's causing my unit tests to crash sporadically.
I'm set up using RestKit with an in-memory object store while unit testing, so that after each test case, I can reset my persistent stores and each test can run with a fresh database. Much of the time my test suite runs without issue, but often enough to be a deal-breaker, there's a crash from what [I think] appears to be over-releasing a managed object context. All relevant code and crash data below:
Unit Test Base Class Setup
#implementation MyTestCase
- (void)setUp
{
[super setUp];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[MyObjectManager sharedManager] start];
});
}
- (void)tearDown
{
[super tearDown];
[[MyObjectManager sharedManager] reset];
}
Relevant MyObjectManager Setup
#interface MyObjectManager : RKObjectManager
- (void)start
{
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithPersistentStoreCoordinator:[self persistentStoreCoordinator]];
self.managedObjectStore = managedObjectStore;
[managedObjectStore createManagedObjectContexts];
[RKManagedObjectStore setDefaultStore:managedObjectStore];
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:kRDPersistentStore];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = #{
NSSQLitePragmasOption : #{
#"synchronous" : #"FULL",
#"fullfsync" : #(1)
},
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES
};
NSError *error = nil;
if (![self persistentStoreAtPath:storeURL options:options error:error])
{
NSLog(#"Error adding store %#: %#, %#", storeURL, error, [error userInfo]);
// Additional handling
}
return _persistentStoreCoordinator;
}
- (NSPersistentStore *)persistentStoreAtPath:(NSURL *)storeURL options:(NSDictionary *)options error:(NSError *)error
{
// (NSSQLiteStoreType and storeUrl are used if we're not unit testing)
return [_persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil
URL:nil
options:options
error:&error];
}
MyObjectManager::reset Implementation
- (void)reset
{
[[RKObjectManager sharedManager].operationQueue cancelAllOperations];
NSError *error = nil;
[[RKManagedObjectStore defaultStore] resetPersistentStores:&error];
if (error)
{
NSLog(#"Error! : %#", error);
}
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
Typical Crash Report
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGSEGV)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
iPhone Simulator 463.9.41, iPhone OS 7.1 (iPhone Retina (4-inch)/11D167)
Main thread is spinning the run loop, waiting on an asynchronous test case:
(Not always the case but a majority of our tests employ this method)
Thread : com.apple.main-thread
0 libsystem_kernel.dylib 0x047f6f92 semaphore_signal_trap + 10
1 libdispatch.dylib 0x0447f41f _dispatch_barrier_sync_f_slow_invoke + 54
2 libdispatch.dylib 0x044904d0 _dispatch_client_callout + 14
3 libdispatch.dylib 0x0447e726 _dispatch_main_queue_callback_4CF + 340
4 CoreFoundation 0x040fb43e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
5 CoreFoundation 0x0403c5cb __CFRunLoopRun + 1963
6 CoreFoundation 0x0403b9d3 CFRunLoopRunSpecific + 467
7 CoreFoundation 0x0403b7eb CFRunLoopRunInMode + 123
8 Foundation 0x03a71e35 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 284
9 Foundation 0x03a71cd5 -[NSRunLoop(NSRunLoop) runUntilDate:] + 88
10 Remind101-Tests 0x0cbb2c02 -[UTTestCase waitForBlockWithTimeout:] + 233
11 Remind101-Tests 0x0cbb2b14 -[UTTestCase waitForBlock] + 49
12 Remind101-Tests 0x0cbba55e -[UTAPITestCase sendRequestExpectingSuccess:] + 142
13 Remind101-Tests 0x0cb92832 -[UTMessageRequestTests testRequestCreatesFileEntities] + 166
14 CoreFoundation 0x0408a91d __invoking___ + 29
15 CoreFoundation 0x0408a82a -[NSInvocation invoke] + 362
16 XCTest 0x20103c6c -[XCTestCase invokeTest] + 221
17 XCTest 0x20103d7b -[XCTestCase performTest:] + 111
18 otest-shim-ios.dylib 0x0098fcc7 XCPerformTestWithSuppressedExpectedAssertionFailures + 172
19 otest-shim-ios.dylib 0x0098fc15 XCTestCase_performTest + 31
20 XCTest 0x20104c48 -[XCTest run] + 82
21 XCTest 0x201033e8 -[XCTestSuite performTest:] + 139
22 XCTest 0x20104c48 -[XCTest run] + 82
23 XCTest 0x201033e8 -[XCTestSuite performTest:] + 139
24 XCTest 0x20104c48 -[XCTest run] + 82
25 XCTest 0x201033e8 -[XCTestSuite performTest:] + 139
26 XCTest 0x20104c48 -[XCTest run] + 82
27 XCTest 0x201066ba +[XCTestProbe runTests:] + 183
28 Foundation 0x03a4b5ec __NSFireDelayedPerform + 372
29 CoreFoundation 0x04054ac6 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
30 CoreFoundation 0x040544ad __CFRunLoopDoTimer + 1181
31 CoreFoundation 0x0403c538 __CFRunLoopRun + 1816
32 CoreFoundation 0x0403b9d3 CFRunLoopRunSpecific + 467
33 CoreFoundation 0x0403b7eb CFRunLoopRunInMode + 123
34 GraphicsServices 0x057495ee GSEventRunModal + 192
35 GraphicsServices 0x0574942b GSEventRun + 104
36 UIKit 0x01e7ff9b UIApplicationMain + 1225
37 Remind101 0x0008d184 main (main.m:16)
38 libdyld.dylib 0x046c5701 start + 1
NSManagedObjectContext Queue thread crashes:
Thread : Crashed: NSManagedObjectContext Queue
0 libobjc.A.dylib 0x03e250be objc_msgSend + 26
1 CoreData 0x0108ffe3 developerSubmittedBlockToNSManagedObjectContextPerform_privateasync + 83
2 libdispatch.dylib 0x044904d0 _dispatch_client_callout + 14
3 libdispatch.dylib 0x0447e047 _dispatch_queue_drain + 452
4 libdispatch.dylib 0x0447de42 _dispatch_queue_invoke + 128
5 libdispatch.dylib 0x0447ede2 _dispatch_root_queue_drain + 78
6 libdispatch.dylib 0x0447f127 _dispatch_worker_thread2 + 39
7 libsystem_pthread.dylib 0x047bfdab _pthread_wqthread + 336
8 libsystem_pthread.dylib 0x047c3cce start_wqthread + 30
There's small variations in the stack of the crashed thread, but it always includes developerSubmittedBlockToNSManagedObjectContextPerform_privateasync in the last couple of frames before a bad objc_msgSend.
My initial hypothesis was that something in my codebase was accessing MyObjectManager.managedObjectContext from off the main thread, which as I understand would be a bad time. But I put in a condition to log and pause if the accessor was called from a thread that was not the main thread, which was never hit, so there goes my low-hanging fruit on that one.
I also tried putting some logging into the entry and exit points of instances of the asynchronous NSManagedObjectContext::performBlock function in the RestKit library to see if a block was running longer than expected, holding onto a reference to the context, and dereferencing it after it had been destroyed. I would have expected a entry log without an exit log if this was the issue, but I didn't see that. I didn't try the same with performBlockAndWait because I'm assuming all synchronous operations are complete by the time my test case finished and resets the persistent store.
I'm really at a loss for even how to go about continuing my investigation into this. I realize it's not a ton to go on, but if anyone has ideas or proposals for tracking this down, I'd be happy to provide more information and try literally anything to get this resolved.
Here's what developerSubmittedBlockToNSManagedObjectContextPerform_privateasync actually does:
Gets a reference to the managed object context from within the queue
Creates it's own autorelease pool
Executes the block
Calls _processRecentChanges: on the managed object context to processing any pending user events
Drains the autorelease pool
Releases the block (the block was copied before it was passed to this method)
If the block was NULL at this point that would be a problem, but you would have different symptoms. The only things here that would use objc_msgSend are the autorelease pool and the message to _processRecentChanges:.
You can try setting a symbolic breakpoint on -[NSManagedObjectContext _processRecentChanges:] and see if that gives you any clues. It's very likely that RestKit is making some invalid assumptions about the lifetime of a managed object context and it's getting over released in your case. If that is true, it's also likely that the opposite error is being made elsewhere - that contexts are being overretained. The two problems more often than not go hand in hand. Your question doesn't include the reported reason for the crash (exception, EXC_BAD_ACCESS, etc.), so it's difficult to be definitive.
_processRecentChanges: gets called a lot, so it may still take some time to track this down. The issue would be easier to troubleshoot with the newer developer tools - you should be able to see what submitted the crashing block and from what queue, and you should be able to use Instruments with your test case. It's likely that if you can reproduce this with the newer tools that you will make progress troubleshooting it much faster.
How to flush damn Core Data objects?
Excuse the wording please, I just want to delete objects for 20 minutes now. Deleting just fine, but Core Data raises exception after a while.
I tried so far:
Delete all objects (MR_truncateAll), then save.
Delete all objects, process pending changes, save.
Turn off undo manager, delete, turn back undo manager.
Delete Core Data sqlite file, destroy context, then recreate.
Use [MagicalRecord cleanUp], delete core data sqlite file.
Still, when I want to create object, after 2-3 attempt, I'll get Faulting, then crash because faulting.
CoreData could not fulfill a fault for '0xd000000000840002 <x-coredata://...
(
0 CoreFoundation 0x0000000102016795 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000101d79991 objc_exception_throw + 43
2 CoreData 0x0000000100265a93 _PFFaultHandlerLookupRow + 1075
3 CoreData 0x00000001002f33a3 -[NSManagedObject(_NSInternalMethods) _updateFromRefreshSnapshot:includingTransients:] + 243
4 CoreData 0x0000000100297563 -[NSManagedObjectContext(_NestedContextSupport) _copyChildObject:toParentObject:fromChildContext:] + 771
5 CoreData 0x000000010029701b -[NSManagedObjectContext(_NestedContextSupport) _parentProcessSaveRequest:inContext:error:] + 1019
6 CoreData 0x00000001002fd243 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke + 563
7 libdispatch.dylib 0x0000000102ce005a _dispatch_barrier_sync_f_slow_invoke + 45
8 libdispatch.dylib 0x0000000102cef6fd _dispatch_client_callout + 8
9 libdispatch.dylib 0x0000000102cdf46c _dispatch_main_queue_callback_4CF + 354
10 CoreFoundation 0x0000000102074729 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
11 CoreFoundation 0x0000000101fc19a4 __CFRunLoopRun + 1764
12 CoreFoundation 0x0000000101fc0ed3 CFRunLoopRunSpecific + 467
13 GraphicsServices 0x00000001032f03a4 GSEventRunModal + 161
14 UIKit 0x0000000100e48a63 UIApplicationMain + 1010
15 GitHub! 0x0000000100002f53 main + 115
16 libdyld.dylib 0x0000000102f9c7e1 start + 0
)
I use a single context. Created by MagicalRecord under the hood.
How do you delete, flush Core Data?
This should work for you
[ClassName MR_truncateAll];
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
ClassName here is the NSManagedObject subclass for your entity.
This works, though I'm not sure if entities really gets deleted (but I hope).
Still shows failing errors on every 2-3th try, but does not throw errors. I just cannt belive that they could not wrap up a [NSPersistentStoreCoordinator deleteEveryStuffSeriouslyNotKidding] method.
// Cut every retaining references.
self.someEntity = nil;
self.entityUsingRelations = nil;
[self.context processPendingChanges];
[[self.context undoManager] disableUndoRegistration];
// You can use simple Core Data `delete` methods.
[SomeEntity MR_truncateAll];
[ReleatiedEntity MR_truncateAll];
[AnotherReleatedEntity MR_truncateAll];
[EntityUsingRelations MR_truncateAll];
[self.context processPendingChanges];
[[self.context undoManager] enableUndoRegistration];
[self.context MR_saveToPersistentStoreAndWait];