I am using Apple's CoreDataBooks sample project as a learning aid for core data.
I modified the app so that when the app loads I show a menu page first - not the Books tableview (RootViewController).
I have done the following:
I created a menu page in interface builder (just a view with a button on it)
The CoreDataBooksAppDelegate.h now looks like this:
// for the menu @class MenuViewController; @interface CoreDataBooksAppDelegate : NSObject <UIApplicationDelegate> { NSManagedObjectModel *managedObjectModel; NSManagedObjectContext *managedObjectContext; NSPersistentStoreCoordinator *persistentStoreCoordinator; UIWindow *window; UINavigationController *navigationController; //for the menu MenuViewController *viewController; } - (IBAction)saveAction:sender; //for the menu @property (nonatomic, retain) IBOutlet MenuViewController *viewController; @property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel; @property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext; @property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator; @property (nonatomic, readonly) NSString *applicationDocumentsDirectory; @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet UINavigationController *navigationController; @end
The CoreDataBooksAppDelegate.m looks like this:
#import "CoreDataBooksAppDelegate.h" #import "RootViewController.h" // for the menu #import "MenuViewController.h" @implementation CoreDataBooksAppDelegate @synthesize window; @synthesize navigationController; // for the menu @synthesize viewController; #pragma mark - #pragma mark Application lifecycle - (void)applicationDidFinishLaunching:(UIApplication *)application { RootViewController *rootViewController = (RootViewController *)[navigationController topViewController]; rootViewController.managedObjectContext = self.managedObjectContext; // for the menu [window addSubview:viewController.view]; // Configure and show the window [window makeKeyAndVisible]; }
The rest of CoreDataAppDelegete.m remains unchanged.
In the MenuViewController when the button is clicked, the following action takes place:
RootViewController *modalViewController1 = [[[RootViewController alloc] initWithNibName:nil bundle:nil] autorelease]; [self presentModalViewController:modalViewController1 animated:YES];
In IB I changed the MainWindow.xib to call the MenuViewController rather than the RootViewController.
So, the app loads and the menu is displayed properly with the button. Upon clicking the button the application crashes inside of the RootViewController's viewDidLoad.
It crashes right here:
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"1 START viewDidLoad RootViewController"); self.title = @"Books"; // Set up the edit and add buttons. self.navigationItem.leftBarButtonItem = self.editButtonItem; NSLog(@"2 setup button viewDidLoad RootViewController"); // Configure the add button. UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addBook)]; self.navigationItem.rightBarButtonItem = addButton; [addButton release]; NSLog(@"3 viewDidLoad RootViewController"); NSError *error; // HERE IS THE CRASH SITE if (![[self fetchedResultsController] performFetch:&error]) { NSLog(@"Does not reach this point in viewDidLoad RootViewController"); // Update to handle the error appropriately. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); // Fail } NSLog(@"END viewDidLoad RootViewController"); }
In the console I receive the following:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Book''
I have read about this exception but I do not know the proper steps to resolve it.
NSManagedObjectModel provides an API to retrieve a stored fetch request by name, and to perform variable substitution—see fetchRequestTemplate(forName:) and fetchRequestFromTemplate(withName:substitutionVariables:) . You typically define fetch request templates using the Data Model editor in Xcode.
Core Data is a framework that you use to manage the model layer objects in your application. It provides generalized and automated solutions to common tasks associated with object life cycle and object graph management, including persistence.
Problem: You see the error message, " Could not merge changes ." Cause: Two different managed object contexts tried to change the same data. This is also known as an optimistic locking failure. Remedy: Either set a merge policy on the context, or manually (programmatically) resolve the failure.
Ok.
Placing the following code inside of the RootViewController's viewDidLoad eliminates the error:
if (managedObjectContext == nil) { managedObjectContext = [(CoreDataBooksAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; NSLog(@"After managedObjectContext: %@", managedObjectContext); }
I found someone with a similar problem here on SO: link text
As Aryeh pointed out in that post: "In short you are trying to fetch an entity from an objectContext that hadn't been set up yet. Your options therefore are to set it up right then or do elsewhere in the app before this view loads."
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With