0

When the user clicks the + button in the navbar, a UIAlert with text prompt comes up. The user then enters a string into the prompt and it should result in a new UITableViewCell with the name as the string.

For some reason the app is crashing when I get to the screen for this viewController.

It think it is related to the following line in ViewDidLoad: NSEntityDescription *entity = [NSEntityDescription entityForName:@"Routine" inManagedObjectContext:managedObjectContext];.

The console says the following: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Routine''

I think I need to use "name" instead of routine but that isn't working either.

Here is my Core Data Model:enter image description here

Here is my code:

#import "RoutineTableViewController.h"
#import "AlertPrompt.h"
#import "Routine.h"

@implementation RoutineTableViewController

@synthesize tableView;
@synthesize eventsArray;
@synthesize managedObjectContext;

    - (void)dealloc
    {
        [managedObjectContext release];
        [eventsArray release];
        [super dealloc];
    }

    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
    }

    #pragma mark - View lifecycle

    - (void)viewDidLoad
    {
        UIBarButtonItem * addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(showPrompt)];
        [self.navigationItem setLeftBarButtonItem:addButton];
        [addButton release];

        UIBarButtonItem *editButton = [[UIBarButtonItem alloc]initWithTitle:@"Edit" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleEdit)];
        self.navigationItem.rightBarButtonItem = editButton;
        [editButton release];

        NSFetchRequest *request = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Routine" inManagedObjectContext:managedObjectContext];
        [request setEntity:entity];

        NSError *error = nil;
        NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
        if (mutableFetchResults == nil) {
            // Handle the error.
        }

        [self setEventsArray:mutableFetchResults];
        [mutableFetchResults release];
        [request release];

        [super viewDidLoad];
    }

    -(void)toggleEdit
    {
        [self.tableView setEditing: !self.tableView.editing animated:YES];

        if (self.tableView.editing)
            [self.navigationItem.rightBarButtonItem setTitle:@"Done"];
        else
            [self.navigationItem.rightBarButtonItem setTitle:@"Edit"];
    }

    -(void)showPrompt
    {
        AlertPrompt *prompt = [AlertPrompt alloc];
        prompt = [prompt initWithTitle:@"Add Workout Day" message:@"\n \n Please enter title for workout day" delegate:self cancelButtonTitle:@"Cancel" okButtonTitle:@"Add"];

        [prompt show];
        [prompt release];
    }

    - (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
    {
        if (buttonIndex != [alertView cancelButtonIndex])
        {
            NSString *entered = [(AlertPrompt *)alertView enteredText];
            if(eventsArray && entered)
            {
                [eventsArray addObject:entered];
                [tableView reloadData];
            }
        }
    }

    -(void)addEvent
    {
        Routine *routine = (Routine *)[NSEntityDescription insertNewObjectForEntityForName:@"Routine" inManagedObjectContext:managedObjectContext];

        NSError *error = nil;
        if (![managedObjectContext save:&error]) {
            // Handle the error.
        }

        [eventsArray insertObject:routine atIndex:0];
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                              withRowAnimation:UITableViewRowAnimationFade];
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }

    - (void)viewDidUnload
    {
        self.eventsArray = nil;
        [super viewDidUnload];
    }

#pragma mark - Table view data source

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return 1;
    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return [eventsArray count];
    }

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            //cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellEditingStyleDelete reuseIdentifier:CellIdentifier] autorelease];
        }
        cell.textLabel.text = [self.eventsArray objectAtIndex:indexPath.row];

        return cell;
    }
    // Override to support conditional editing of the table view.
    - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // Return NO if you do not want the specified item to be editable.
        return YES;
    }

    -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
     {

         if (editingStyle == UITableViewCellEditingStyleDelete) {

             // Delete the managed object at the given index path.
             NSManagedObject *eventToDelete = [eventsArray objectAtIndex:indexPath.row];
             [managedObjectContext deleteObject:eventToDelete];

             // Update the array and table view.
             [eventsArray removeObjectAtIndex:indexPath.row];
             [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];

             // Commit the change.
             NSError *error = nil;
             if (![managedObjectContext save:&error]) {
                 // Handle the error.
             }
         }
     }    
    @end

2 Answers2

1

I'm not seeing where your ManagedObjectContext is declared and hooked into your existing data model. As in, where do you declare your "getter" for accessing it from the persistentStoreCoordinator. Try checking your connection and inserting on viewDidLoad. And check the documentation steps here:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdUsingMOM.html#//apple_ref/doc/uid/TP40005190-SW1

Here's an example of it hooking into your perstistantStoreCoordinator

- (NSManagedObjectContext *) managedObjectContext {

if (managedObjectContext != nil) {
    return managedObjectContext;
}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
    managedObjectContext = [[NSManagedObjectContext alloc] init];
    [managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;

}

Or from the tutorial you're using, you'll see it in the application delegate's didFinishLaunching method :

NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
    // Handle the error.
}
// Pass the managed object context to the view controller.
rootViewController.managedObjectContext = context;

EDIT

After reviewing your code, you need to do two things :

1) edit your AppDelegate to load the "Curl" model, not the "Temp" model. That's the name of your xdatamodel.

2) You need to reference your app delegate's context and NOT make one locally. I.e.

CurlAppDelegate *curlAppDelegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [curlAppDelegate managedObjectContext];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Routine" inManagedObjectContext:context];
    [request setEntity:entity];

    NSError *error = nil;
    NSMutableArray *mutableFetchResults = [[context executeFetchRequest:request error:&error] mutableCopy];
    if (mutableFetchResults == nil) {
        // Handle the error.
    }
Dominic Tancredi
  • 41,134
  • 7
  • 34
  • 50
  • I'm following the tutorial posted here (http://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/iPhoneCoreData01/Articles/04_Adding.html%23//apple_ref/doc/uid/TP40008305-CH106-SW1) and they don't seem to use those methods that you have. Or am I missing that? –  Mar 28 '11 at 05:43
  • I added the code you posted and it seems like everything should be ok, but it is still not working. –  Mar 28 '11 at 07:13
  • In the tutorial (which is excellent), you should setup your context in the application delegate. Did you do that? And make sure that the xdatamodel is saved? Do you have a link to your project zipped somewhere and I can debug it? Here's the page that explains the setup : http://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/iPhoneCoreData01/Articles/02_RootViewController.html#//apple_ref/doc/uid/TP40008305-CH104-SW1 – Dominic Tancredi Mar 28 '11 at 11:49
  • Thanks, Dominic. I'm going to go back over that tutorial to see if I missed anything. Here is the link to my project zipped: http://www.box.net/shared/static/colensfm58.zip. Thanks –  Mar 28 '11 at 14:14
  • Thanks Dominic, that fixed the crash and the view works now. But for some reason it is not saving the data and fetching it upon the next start of the app. I'll look over the code once again I might have forgot to implement the fetch requests. –  Mar 29 '11 at 01:45
  • yup just double checked and the fetch request is indeed there under viewDidLoad. Any idea why its not showing the data when the app is hard exited and then relaunched? –  Mar 29 '11 at 02:09
  • I can check it out tomorrow, but my guess is that you're loading the "Temp" sqlite and not the "Curl" sqlite file. You can see it in your app delegate. If that file doesn't exist, it just recreates a new database, saves it to sqlite in your Documents folder in the simulator's directory. Since you're not properly looking for the right databased to reload... it recreates it! Change "Temp" to "Curl". – Dominic Tancredi Mar 29 '11 at 03:03
  • Actually it turns out the solution was not correct, just a workaround, as these guys here told me that that method should not be in my viewcontroller. I'm now back to square one and view is crashing. You can see my other question here: http://stackoverflow.com/questions/5467193/why-isnt-core-data-fetching-my-data/5467295#5467295 –  Mar 30 '11 at 00:28
  • The solution works with what you were trying to do... which was have references to your managedObjectContext in your viewcontroller. I didn't ask why you did that, just helped you debug how you would solve it doing that. I recommend, based on what they're saying, to just have a single DatabaseManager in your AppDelegate that manages all your CoreData and referencing it as a singleton where-ever you need to use it. Local versions, especially with a TabBar, can get mega-confusing. – Dominic Tancredi Mar 30 '11 at 12:40
0

The "NSInternalInconsistencyException" error is related to having changed your underlying data model to the extent that Core Data can't perform an automatic lightweight data migration: the actual SQLite or plist file you're using to store your data is now incompatible with the new structure of the data model.

To clear it up you can either just delete the app from the simulator (or device, if that's where you're testing) the usual way -- pressing and holding the app icon until it wiggles and then tapping/clicking the X -- or by deleting the file itself from the app's working directory on your Mac.

~/Library/Application Support/iPhone Simulator/YOUR-IOS-BASE-SDK-HERE/Applications/YOUR-36-BYTE-APP-ID-HERE/Documents

(Or if not Documents, whichever folder you used.)

After that you can run the app that this particular error will disappear because Core Data will be able to create the file from scratch again.

Matthew Frederick
  • 22,245
  • 10
  • 71
  • 97