views:

3199

answers:

3

Hi,

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]);
  exit(-1);  // 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.

Any help would be appreciated.

Thank-you for your time, Vivas

A: 

Did you change the Core Data model at all? That error is common when the Core Data model for an app changes without also changing the underlying SQLite database, so the stored data and the model are out of sync.

Try completely removing your app from the Simulator or testing device, then reinstalling it and trying again.

Tim
Vivas
Step through the program in the debugger - what's the value of `managedObjectModel` when you get the exception? `managedObjectContext`?
Tim
Hi. Okay in the debugger I don't see managedObjectModel - but what I do see is that the value for managedObjectContext is null in the RootViewController viewDidLoad - which is wrong, it should have a value there. In the unmodified version of the app the value of the managedObjectContext is 0x3e2ce60 in the viewDidLoad.and the debugger stops on this line:NSEntityDescription *entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:managedObjectContext];Which is inside - (NSFetchedResultsController *)fetchedResultsController method of the RootViewController.
Vivas
OK, so your issue is likely the fact that `managedObjectContext` is `nil` - you can't get an entity description in a nonexistent context. I'd check to see what you're doing with your context in code that you added that may cause it to be deallocated or not present at that line.
Tim
A: 

In applicationDidFinishLaunching: you're doing the following:

rootViewController.managedObjectContext = self.managedObjectContext;

But I don't see the code where self.managedObjectContext is setup. applicationDidFinishLaunching is called pretty early on. Are you sure you setup the managed object context?

Doug Richardson
Hi Doug. Yes, managed object context is setup (this is the CoreDataBooks sample from Apple, I was just adding a menu so I left the rest of the code untouched). In applicationDidFinishLaunching if I replace the line: [window addSubview:viewController.view]; with the line: [window addSubview:[navigationController view]]; (see above in my question posting) then the app loads the RootViewController right away, runs fine and the managedObjectContext is not nil. Either way, in the applicationDidFinishLaunching, managedObjectContext has a value: <NSManagedObjectContext: 0x3e2d030>. Thanks.
Vivas
+2  A: 

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

Vivas
Thank you! This really helped!
Nic Hubbard