ios could not locate NSManagedObjectModel , NSInternalConsistencyException - ios

I know similar questions have been asked but they all have different answers and none seem to help me.
So, I've got an app called TherapistScheduler, which has therapistScheduler.xcdatamodel in a /Data folder at the root of the project. Inside that folder is a Session.h and Session.m file, which match up with my Session entity in my data model.
My app delegate has the functions managedObjectContext, managedObjectModel, and persistantStoreCoodinator in it.
Inside my applicationDidFinishLaunching method, I've added a view controller (loginViewController) over the top of my rootViewController (which is a tabBarController), and I'm trying to access my Session entity from there.
I'm using the following code to try and save a value - this is throwing the error:
// create session
Session *session = (Session *) [NSEntityDescription insertNewObjectForEntityForName:#"Session" inManagedObjectContext:self.managedObjectContext];
[session setSessionHash:strUserhash];
The loginViewController.h file contains:
NSManagedObjectContext *managedObjectContext; // in the interface declaration
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext; // after the interface
The loginViewController.m file contains
#synthesize managedObjectContext;
Do I need to do something in the loginViewController viewDidLoad to initialise the managedObjectContext? I'm a bit lost as to how this all works. I want to be able to access the data stored in the managedObjectContext from any view I switch to on the tab bar.
I know I'll probably need to add more code to the question, but I don't know what else is needed.
The error I'm getting is this:
TherapistScheduler[40752:207] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Session''
*** Call stack at first throw:
(
0 CoreFoundation 0x02581919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x0295b5de objc_exception_throw + 47
2 CoreData 0x0004525b +[NSEntityDescription entityForName:inManagedObjectContext:] + 187
3 CoreData 0x0007cd8b +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:] + 59
4 TherapistScheduler 0x000030ce -[LoginViewController processLoginForUserhash:andType:] + 142
5 TherapistScheduler 0x000039fa -[LoginViewController connectionDidFinishLoading:] + 330
6 Foundation 0x01f91666 -[NSURLConnection(NSURLConnectionReallyInternal) sendDidFinishLoading] + 108
7 Foundation 0x01f915bf _NSURLConnectionDidFinishLoading + 133
8 CFNetwork 0x02b8d9f1 _ZN19URLConnectionClient23_clientDidFinishLoadingEPNS_26ClientConnectionEventQueueE + 285
9 CFNetwork 0x02c56c72 _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 402
10 CFNetwork 0x02c570ea _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 1546
11 CFNetwork 0x02c570ea _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 1546
12 CFNetwork 0x02b82dfe _ZN19URLConnectionClient13processEventsEv + 100
13 CFNetwork 0x02b82c95 _ZN17MultiplexerSource7performEv + 247
14 CoreFoundation 0x02562d7f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
15 CoreFoundation 0x024c11dd __CFRunLoopDoSources0 + 333
16 CoreFoundation 0x024c07c6 __CFRunLoopRun + 470
17 CoreFoundation 0x024c0280 CFRunLoopRunSpecific + 208
18 CoreFoundation 0x024c01a1 CFRunLoopRunInMode + 97
19 GraphicsServices 0x02de62c8 GSEventRunModal + 217
20 GraphicsServices 0x02de638d GSEventRun + 115
21 UIKit 0x00215b58 UIApplicationMain + 1160
22 TherapistScheduler 0x00001f3d main + 125
23 TherapistScheduler 0x00001eb5 start + 53
24 ??? 0x00000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'

I had to refer to the managedObjectContext as a property of the app delegate not self. So it looked like appDelegate.managedObjectContext.

When you passed the managedObjectContext, I think what you did is like this:
TimelineTableViewController * timelineTableViewController;
timelineTableViewController = [TimelineTableViewController alloc];
[timelineTableViewController initWithStyle:UITableViewStylePlain];
timelineTableViewController.managedObjectContext = self.managedObjectContext;
//...
and then in TimelineTableViewController's viewDidLoad: method, you wanted to fetch the data by managedObjectContext, huh?
I debugged this issue and found that TimelineTableViewController's viewDidLoad: will be dispatched quicker than timelineTableViewController.managedObjectContext = self.managedObjectContext; (where you passed the managedObjectContext from parent (or the AppDelegate) to child). So when you were trying to fetch the data, the managedObjectContext is nil actually. That's why you got this issue:
'+entityForName: could not locate an NSManagedObjectModel for entity name 'Session''
WORKAROUND:
What you have to do is to make sure that the managedObjectContext is not nil when you need to fetch the data:
TimelineTableViewController * timelineTableViewController;
timelineTableViewController = [TimelineTableViewController alloc];
timelineTableViewController.managedObjectContext = self.managedObjectContext;
[timelineTableViewController initWithStyle:UITableViewStylePlain];
// ...
I just solved this issue by this way (no need to use AppDelegate's managedObjectContext directly).

Related

EXC_BAD_ACCESS when object released mid-function

I have a class with a property
#property (nonatomic, copy) MyObject *currentObject;
and a function that looks like this:
- (void)handleExternalChange {
#synchronized (self) {
MyObject *newObject = [self.externalStore getObject];
//Business logic...
self.currentObject = newObject;
}
}
I am seeing a crash objc_msgSend() selector name: copyWithZone: occasionally when i hit the self.currentObject = newObject line.
I presume this is because the externalStore released the object returned by getObject on another thread and by the time it got down to the setter it was gone.
Does this conclusion seem right? If so is there a recommended way to fix this?
UPDATE:
Here's some of the stack trace
Application Specific Information:
objc_msgSend() selector name: copyWithZone:
0 libobjc.A.dylib 0x000000018149ef30 objc_msgSend + 16
1 libobjc.A.dylib 0x000000018149c2d4 objc_setProperty_nonatomic_copy + 44
2 MyApp 0x0000000100115cb4 -[MyClass handleExternalChange] (MyClass.m:117)
3 CoreFoundation 0x00000001829ee22c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 16
4 CoreFoundation 0x00000001829ed930 _CFXRegistrationPost + 396
5 CoreFoundation 0x00000001829ed6ac ___CFXNotificationPost_block_invoke + 56
6 CoreFoundation 0x0000000182a5cb9c -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1500
7 CoreFoundation 0x000000018292fbf4 _CFXNotificationPost + 372
8 Foundation 0x00000001834366bc -[NSNotificationCenter postNotificationName:object:userInfo:] + 64
MyObject *newObject = [self.externalStore getObject];
That method shouldn't be named get* anything, but that isn't likely to be the cause of the issue. Nor is it likely to be a threading issue (at least not directly).
This sounds more like there is some state related to the copyWithZone: that isn't handled correctly. How is the copy method implemented? Specifically, is it correctly copying all state and bumping reference counts or does it try to cheat by doing some kind of a byte copy?

Trials and tribulations of changing NSOrderedSet order in Core Data

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.

Crash when Fetched Results Controller updates table after saving a background MOC

I have a tableView hooked up to a FRC (Fetched Results Controller) , I also have two contexts , namely backgroundContext initialised in a private queue and a mainContext initialised on the main queue. I also have setup the didSaveNotification to pass the objects from one context to another. When ever i save some data in the backgroundContext it saves successfully and FRC updates ,but if i repeat the process again the app crashes with an error
'The left hand side for an ALL or ANY operator must be either an
NSArray or an NSSet.'
The saving is done through a form which is presented modally. The same viewController works fine if presented in other viewControllers . but crashes only in one particular one. But again other that presenting the Form no other extra stuff is being done.
Here's my entire crash report.
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'The left hand side for an ALL
or ANY operator must be either an NSArray or an NSSet.'
* First throw call stack: ( 0 CoreFoundation 0x0000000103575495 exceptionPreprocess + 165 1 libobjc.A.dylib
0x0000000102fbb99e objc_exception_throw + 43 2 Foundation
0x00000001003c706b -[NSPredicateOperator
performOperationUsingObject:andObject:] + 826 3 Foundation
0x00000001003c6c1e -[NSComparisonPredicate
evaluateWithObject:substitutionVariables:] + 314 4 Foundation
0x00000001003c6ae2 -[NSPredicate evaluateWithObject:] + 19 5
CoreData 0x0000000102d61d06
-[NSFetchedResultsController(PrivateMethods) _objectInResults:] + 102 6 CoreData 0x0000000102d630f7
-[NSFetchedResultsController(PrivateMethods) _preprocessUpdatedObjects:insertsInfo:deletesInfo:updatesInfo:sectionsWithDeletes:newSectionNames:treatAsRefreshes:]
+ 519 7 CoreData 0x0000000102d642d5 -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 1781 8 CoreFoundation 0x00000001035cad9c
__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER + 12 9 CoreFoundation 0x000000010352d51d
_CFXNotificationPost + 2381 10 Foundation 0x000000010035b7fa -[NSNotificationCenter
postNotificationName:object:userInfo:] + 68 11 CoreData
0x0000000102c9048a
-[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 74 12 CoreData 0x0000000102d16c8b
-[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:]
+ 331 13 CoreData 0x0000000102c8c9cc -[NSManagedObjectContext(_NSInternalChangeProcessing) _postRefreshedObjectsNotificationAndClearList] + 108 14 CoreData 0x0000000102c8c5e4
-[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2804 15 CoreData 0x0000000102c663cb _performRunLoopAction + 267 16 CoreFoundation
0x0000000103540dc7
CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 23 17 CoreFoundation 0x0000000103540d37
__CFRunLoopDoObservers + 391 18 CoreFoundation 0x0000000103520522 __CFRunLoopRun + 946 19 CoreFoundation
0x000000010351fd83 CFRunLoopRunSpecific + 467 20 GraphicsServices
0x00000001037ecf04 GSEventRunModal + 161 21 UIKit
0x00000001011bde33 UIApplicationMain + 1010 22 Expense_Manager
0x0000000100001d13 main + 115 23 libdyld.dylib
0x000000010420c7e1 start + 0 ) libc++abi.dylib: terminating with
uncaught exception of type NSException
Thanks in advance.
Okay i actually found out why this was happening a few days ago. There was a notification being fired off when the form dismissed which reloaded a tableView from another viewController hooked up to an FRC sharing the same context. Once I removed itself as an observer in viewDidDisappear it did not crash. :) I hope this helps incase someone is facing the same problem.

How do I fix this crash when merging core data content from context?

I have a core data project. When I do a pull to refresh on the table view, it creates a new context on a background thread, updates the database, and then merges those updates to the main context. Everything was working okay (I think), but now I'm getting the following crash:
2013-09-13 19:01:40.873 My App[2926:a0b] -[__NSCFString controllerWillChangeContent:]: unrecognized selector sent to instance 0xc26b370
2013-09-13 19:02:00.629 My App[2926:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString controllerWillChangeContent:]: unrecognized selector sent to instance 0xc26b370'
*** First throw call stack:
(
0 CoreFoundation 0x027795e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x01e888b6 objc_exception_throw + 44
2 CoreFoundation 0x02816903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x0276990b ___forwarding___ + 1019
4 CoreFoundation 0x027694ee _CF_forwarding_prep_0 + 14
5 CoreData 0x002217b0 -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 2080
6 Foundation 0x015dbe39 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke + 40
7 CoreFoundation 0x027d5524 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
8 CoreFoundation 0x0272d07b _CFXNotificationPost + 2859
9 Foundation 0x01515b91 -[NSNotificationCenter postNotificationName:object:userInfo:] + 98
10 CoreData 0x001264a3 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 83
11 CoreData 0x0013be96 -[NSManagedObjectContext _mergeChangesFromDidSaveDictionary:usingObjectIDs:] + 3734
12 CoreData 0x0013afed -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] + 429
13 My App 0x0000bc45 -[MAManager updateMainContext:] + 245
14 libobjc.A.dylib 0x01e9a81f -[NSObject performSelector:withObject:] + 70
15 Foundation 0x0155dc18 __NSThreadPerformPerform + 285
16 CoreFoundation 0x027028af __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
17 CoreFoundation 0x0270223b __CFRunLoopDoSources0 + 235
18 CoreFoundation 0x0271f30e __CFRunLoopRun + 910
19 CoreFoundation 0x0271eb33 CFRunLoopRunSpecific + 467
20 CoreFoundation 0x0271e94b CFRunLoopRunInMode + 123
21 GraphicsServices 0x0348e9d7 GSEventRunModal + 192
22 GraphicsServices 0x0348e7fe GSEventRun + 104
23 UIKit 0x0067b94b UIApplicationMain + 1225
24 My App 0x00003442 main + 146
25 libdyld.dylib 0x0236d725 start + 0
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Here is the relevant bit of code that it's breaking on:
// merge changes to main context,fetchedRequestController will automatically monitor the changes and update tableview.
- (void)updateMainContext:(NSNotification *)notification {
assert([NSThread isMainThread]);
NSLog(#"Merging changes from context.");
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
[self save]; // update fetched results controllers
}
// this is called via observing "NSManagedObjectContextDidSaveNotification" from the background thread data load
- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification {
NSLog(#"Context saved!");
if (notification.object != [self managedObjectContext]) {
NSLog(#"Background context propagating to main context.");
[self performSelectorOnMainThread:#selector(updateMainContext:) withObject:notification waitUntilDone:NO];
}
}
Does anyone know why I'm getting this error and how to fix it?
Some object that is registered for a notification looks to have been released and its address re-used to store a string instead of what's expected.
Turn on zombies for your scheme, run it again, and figure out which object is being sent the notification. Then make sure you're keeping the object alive while you need it.
Your crash is an unrecognized selector with the method [__NSCFString controllerWillChangeContent:]. This method is called on the delegate of a FRC, yet somehow you have the call back performed on an NSString, which doesn't implement that method. Can you post the code where you set up your NSFetchedResultsController in that viewController?
It seems it was a problem with multiple save requests coming in concurrently (from different managed object contexts, but different threads nonetheless). The solution was to wrap the save operations in a #synchronized block to ensure that the save operations were atomic and did not happen concurrently:
- (void) save {
// lock and wait if another save operation is in progress
#synchronized([self class]) {
NSError *error;
if (![self save:&error]) {
NSLog(#"Whoops, couldn't save: %#", error);
}
}
}

Memory management error on persistent store error

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).

Resources