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.
Related
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'
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.
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];
With my App I have a pre-populated sqlite DB that I created using core data from another app I created so the Data model is the same. I copy it over and everything works great. I tried it on every iOS device that can run iOS 6.0 because that is what I am building for. Even on the early iPod Touches the App works. It takes around 45 secs for the DB to copy over on the older devices. The app works all the data is there and all devices the tests were great and no issues. I released the app on the app store and found out that on the older devices the app is crashing when it first loads. I am assuming that it is a memory related issue. I am mostly confused that the customers that purchased it that I am in communication with have the same phone an iPhone 4S and one reports it works fine while the other says it crashes. I am thinking that one has a early 4S while the other has a later 4S. I confirmed that they had room on the phone to copy the data also. When I run the app from Xcode it never crashes no matter the device.
My Question is does any one know why this is happening and a possible fix?
Maybe there is a more efficient way that doesn't make the app take almost a min to load for the first time? Any help would be great because I am at a loss. I looked at about 30 other questions that are some what like this one but they really don't answer the question I need.
I would also just like to say Thank You to all of You because I live on this site and have learned a lot from all your questions and Answers.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Data.sqlite"];
#define UPGRADE_COPY_STORE_FROM_BUNDLE
#ifdef UPGRADE_COPY_STORE_FROM_BUNDLE
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURL path]]) {
NSString *dataPath = [[NSBundle mainBundle]pathForResource:#"Data" ofType:#"sqlite" inDirectory:nil];
NSError *anyError = nil;
BOOL success = [[NSFileManager defaultManager] copyItemAtPath:dataPath toPath:[storeURL path] error:&anyError];
if (!success) NSLog(#"Error copying file: %#", anyError);
}
#endif
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
return _persistentStoreCoordinator;
}
Also attached is the Crash Log from a Device. Updated
Incident Identifier: CCFB748D-5A2A-45CE-B9EC-19811CCDC696
CrashReporter Key: 71b2c2b3b88abfe03baa87e7f588642dcec0ff08
Hardware Model: iPod4,1
Process: Upgrade [2513]
Path: /var/mobile/Applications/27C440D4-0210-48BB-A287-570FAEDE3369/Upgrade.app/Upgrade
Identifier: Upgrade
Version: ??? (???)
Code Type: ARM (Native)
Parent Process: launchd [1]
Date/Time: 2013-07-27 23:23:57.479 -0600
OS Version: iOS 6.1.2 (10B146)
Report Version: 104
Exception Type: 00000020
Exception Codes: 0x000000008badf00d
Highlighted Thread: 0
Application Specific Information:
com.JonPhillips.Upgrade failed to launch in time
Elapsed total CPU time (seconds): 2.450 (user 2.450, system 0.000), 12% CPU
Elapsed application CPU time (seconds): 0.528, 3% CPU
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0:
0 libsystem_kernel.dylib 0x39b84570 read + 8
1 libcopyfile.dylib 0x39a70df4 copyfile_internal + 4616
2 libcopyfile.dylib 0x39a72196 copyfile + 3326
3 Foundation 0x32301cb4 -[NSFilesystemItemCopyOperation _handleFTSEntry:] + 384
4 Foundation 0x323014a2 -[NSDirectoryTraversalOperation main] + 334
5 Foundation 0x322af5bc -[__NSOperationInternal start] + 836
6 Foundation 0x322fdd1e -[NSFileManager copyItemAtPath:toPath:error:] + 238
7 Upgrade 0x0009f438 -[JPPAppDelegate persistentStoreCoordinator] (JPPAppDelegate.m:186)
8 Upgrade 0x0009ef30 -[JPPAppDelegate managedObjectContext] (JPPAppDelegate.m:150)
9 Upgrade 0x0009f95e -[MainScreenViewController viewDidLoad] (MainScreenViewController.m:35)
10 UIKit 0x33849590 -[UIViewController loadViewIfRequired] + 360
11 UIKit 0x338c3fb8 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 80
12 UIKit 0x338c3f5e -[UITabBarController transitionFromViewController:toViewController:] + 26
13 UIKit 0x3386e05c -[UITabBarController _setSelectedViewController:] + 292
14 UIKit 0x3386e642 -[UITabBarController _selectDefaultViewControllerIfNecessaryWithAppearanceTransitions:] + 150
15 UIKit 0x338c6ca2 -[UITabBarController viewWillAppear:] + 130
16 UIKit 0x3389130c -[UIViewController _setViewAppearState:isAnimating:] + 132
17 UIKit 0x33849e10 -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:] + 504
18 UIKit 0x3382c40e -[UIView(Internal) _addSubview:positioned:relativeTo:] + 326
19 UIKit 0x3382c2be -[UIView(Hierarchy) addSubview:] + 26
20 UIKit 0x33889e46 -[UIWindow addRootViewControllerViewIfPossible] + 270
21 UIKit 0x33885ae8 -[UIWindow _setHidden:forced:] + 360
22 UIKit 0x338c71e4 -[UIWindow makeKeyAndVisible] + 56
23 Upgrade 0x0009e896 -[JPPAppDelegate initializeStoryBoardBasedOnScreenSize] (JPPAppDelegate.m:64)
24 Upgrade 0x0009e106 -[JPPAppDelegate application:didFinishLaunchingWithOptions:] (JPPAppDelegate.m:22)
25 UIKit 0x3388aad4 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 248
26 UIKit 0x3388a65e -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1186
27 UIKit 0x33882846 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 694
28 UIKit 0x3382ac34 -[UIApplication handleEvent:withNewEvent:] + 1000
29 UIKit 0x3382a6c8 -[UIApplication sendEvent:] + 68
30 UIKit 0x3382a116 _UIApplicationHandleEvent + 6150
31 GraphicsServices 0x3551a5a0 _PurpleEventCallback + 588
32 GraphicsServices 0x3551a1ce PurpleEventCallback + 30
33 CoreFoundation 0x319f7170 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32
34 CoreFoundation 0x319f7112 __CFRunLoopDoSource1 + 134
35 CoreFoundation 0x319f5f94 __CFRunLoopRun + 1380
36 CoreFoundation 0x31968eb8 CFRunLoopRunSpecific + 352
37 CoreFoundation 0x31968d44 CFRunLoopRunInMode + 100
38 UIKit 0x33881480 -[UIApplication _run] + 664
39 UIKit 0x3387e2fc UIApplicationMain + 1116
40 Upgrade 0x0009e0b8 main (main.m:16)
41 libdyld.dylib 0x39accb1c start + 0
Thread 1 name: Dispatch queue: com.apple.libdispatch-manager
Thread 1:
0 libsystem_kernel.dylib 0x39b83648 kevent64 + 24
1 libdispatch.dylib 0x39abc4ec _dispatch_mgr_invoke + 792
2 libdispatch.dylib 0x39aaedf4 _dispatch_mgr_thread$VARIANT$up + 32
Thread 2 name: WebThread
Thread 2:
0 libsystem_kernel.dylib 0x39b82eb4 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x39b83048 mach_msg + 36
2 CoreFoundation 0x319f7040 __CFRunLoopServiceMachPort + 124
3 CoreFoundation 0x319f5d9e __CFRunLoopRun + 878
4 CoreFoundation 0x31968eb8 CFRunLoopRunSpecific + 352
5 CoreFoundation 0x31968d44 CFRunLoopRunInMode + 100
6 WebCore 0x3794c500 RunWebThread(void*) + 440
7 libsystem_c.dylib 0x39aec30e _pthread_start + 306
8 libsystem_c.dylib 0x39aec1d4 thread_start + 4
Unknown thread crashed with unknown flavor: 5, state_count: 1
You are copying the data on the main thread, which blocks it far too long. It should never ever be blocked for 1 second or longer. Otherwise the iOS watchdog will kill your process.
The specific crash report shows the app was killed, because it took too long to start up: com.JonPhillips.Upgrade failed to launch in time.
The copy action is even running from inside applicationDidFinishLaunching. The watchdog timer is even shorter for having this method end! Check the WWDC sessions for exact timing if you are interested in them. I don't recall in which specifically it was mentioned.
If you require such tasks, move them to a background thread. If this tasks means that the user cannot do anything in the app, show a specific UI telling the user what is going on and giving some indication how long it will take, e.g. a progress bar, and/or some text "Step 1 of 3: Copying data".
I am getting an error that seems pretty clearly to be a message to a deallocated object, but I cannot figure out where I am managing memory wrong. This is my code to create the persistent store coordinator. It's based on the Core Data application template. I might have changed it a bit, but not much I think.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
/* Reminder: in Simulator this is in /Users/<username>/Library/Application Support/iPhone Simulator/User/Applications/<bundleid>/Documents/Wordfare.sqlite */
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"Wordfare.sqlite"]];
NSError *error;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
[persistentStoreCoordinator release];
persistentStoreCoordinator = nil;
}
return persistentStoreCoordinator;
}
The problem happens when I get an error from addPersistentStore, because I changed my model and I'm trying to open a store that was created with the previous model. Of course one answer is, "Don't do that." I won't, but I want the code to be robust. The above code runs without complaint, but then when I press the home button, the app crashes with this error:
2011-11-02 16:39:53.751 Wordfare[11137:207] -[__NSCFArray tryLock]: unrecognized selector sent to instance 0x5a122f0
2011-11-02 16:39:53.783 Wordfare[11137:207] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray tryLock]: unrecognized selector sent to instance 0x5a122f0'
* Call stack at first throw:
(
0 CoreFoundation 0x012ed5a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x01441313 objc_exception_throw + 44
2 CoreFoundation 0x012ef0bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x0125e966 forwarding + 966
4 CoreFoundation 0x0125e522 _CF_forwarding_prep_0 + 50
5 CoreData 0x010d9ef0 -[_NSSQLCoreConnectionObsever _purgeCaches:] + 112
6 Foundation 0x00370669 _nsnote_callback + 145
7 CoreFoundation 0x012c59f9 __CFXNotificationPost_old + 745
8 CoreFoundation 0x0124493a _CFXNotificationPostNotification + 186
9 Foundation 0x0036620e -[NSNotificationCenter postNotificationName:object:userInfo:] + 134
10 UIKit 0x0060aa0b -[UIApplication _handleApplicationSuspend:eventInfo:] + 554
11 UIKit 0x00614039 -[UIApplication handleEvent:withNewEvent:] + 4127
12 UIKit 0x0060babf -[UIApplication sendEvent:] + 71
13 UIKit 0x00610f2e _UIApplicationHandleEvent + 7576
14 GraphicsServices 0x03851992 PurpleEventCallback + 1550
15 CoreFoundation 0x012ce944 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION + 52
16 CoreFoundation 0x0122ecf7 __CFRunLoopDoSource1 + 215
17 CoreFoundation 0x0122bf83 __CFRunLoopRun + 979
18 CoreFoundation 0x0122b840 CFRunLoopRunSpecific + 208
19 CoreFoundation 0x0122b761 CFRunLoopRunInMode + 97
20 GraphicsServices 0x038501c4 GSEventRunModal + 217
21 GraphicsServices 0x03850289 GSEventRun + 115
22 UIKit 0x00614c93 UIApplicationMain + 1160
23 Wordfare 0x00002224 main + 102
24 Wordfare 0x000021b5 start + 53
)
terminate called after throwing an instance of 'NSException'
Sorry for the double-spacing. I couldn't figure out the formatting.
It looks like an __NSCFArray has happened to move in after the persistent store coordinator was deallocated, but something still has a pointer to the persistent store and is trying to call its tryLock.
It's really hard to tell what that could be. I allocate the persistent store coordinator, call addPersistentStore, then release it and set it to nil. Nothing in my code could have got a reference to it outside that method. The only thing I can imagine getting a reference to it would be the managedObjectModel. I tried releasing that too but that got a different error.
If I comment out the line that releases persistentStoreCoordinator, and just set it to nil, then it runs fine, but that can't be right. persistentStoreCoordinator is an instance variable of course. I allocated it; I should release it if I'm discarding the reference to it.
How am I supposed to clean up a persistent store coordinator after an error?
Additional: I have confirmed that the unrecognized selector is getting sent to the memory address of the persistent store coordinator.
Not a Core Data answer, but you should run with zombies enabled (in recent Xcodes, just hit the checkbox in the Debug part of the scheme).