Hello. I am a newbie, so please excuse my lack of correct terminology. I have code similar to Core Data Recipes, where a category is selected on the detail view. I thought that my problem was being caused because I was trying to display category section headings on the root view, so I changed some data in Recipes and was able to replicate the problem. Basically, I crash every time I try to add a new row, either on the selection of the category or on the save. The error is:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSManagedObject compare:]: unrecognized selector sent to instance 0x3e4e140'
It seems like if I choose a category that has already been selected for an existing recipe, everything goes well. But if I even select a "new" category, crash. I have tried a ton of things from the internet to no avail. But like I said, I am new at this. I thought someone might be able to download the code from the website and change what I changed to reproduce. I'm sure I am missing something obvious. Please help!
To modify Recipe, I added numberOfSectionsInTableView and titleForHeaderInSection. I altered fetchedResultsController sort descriptors and section name key path. That's it, I'm pretty sure. I think that this code had problems before I got my hands on it... but I would really appreciate it if anyone knows how to get it working.
Here is the link to download the "pristine" code from Apple:
http://developer.apple.com/iphone/library/samplecode/iPhoneCoreDataRecipes/index.html
Here is the modified code from RecipeListTableViewController.m:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSManagedObject compare:]: unrecognized selector sent to instance 0x3e4e140'
It seems like if I choose a category that has already been selected for an existing recipe, everything goes well. But if I even select a "new" category, crash. I have tried a ton of things from the internet to no avail. But like I said, I am new at this. I thought someone might be able to download the code from the website and change what I changed to reproduce. I'm sure I am missing something obvious. Please help!
To modify Recipe, I added numberOfSectionsInTableView and titleForHeaderInSection. I altered fetchedResultsController sort descriptors and section name key path. That's it, I'm pretty sure. I think that this code had problems before I got my hands on it... but I would really appreciate it if anyone knows how to get it working.
Here is the link to download the "pristine" code from Apple:
http://developer.apple.com/iphone/library/samplecode/iPhoneCoreDataRecipes/index.html
Here is the modified code from RecipeListTableViewController.m:
Code:
#pragma mark -
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger count = [[fetchedResultsController sections] count];
if (count == 0) {
count = 1;
}
return count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger numberOfRows = 0;
if ([[fetchedResultsController sections] count] > 0) {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
numberOfRows = [sectionInfo numberOfObjects];
}
return numberOfRows;
}
// NOT IN RECIPE or CORE DATA LOCATION TUTORIAL
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
// Display the types' names as section headings.
// return [[[fetchedResultsController sections] objectAtIndex:section] valueForKey:@"name"];
if (fetchedResultsController.sections.count > 0) {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo name];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Dequeue or if necessary create a RecipeTableViewCell, then set its recipe to the recipe for the current row.
static NSString *RecipeCellIdentifier = @"RecipeCellIdentifier";
RecipeTableViewCell *recipeCell = (RecipeTableViewCell *)[tableView dequeueReusableCellWithIdentifier:RecipeCellIdentifier];
if (recipeCell == nil) {
recipeCell = [[[RecipeTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RecipeCellIdentifier] autorelease];
recipeCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
[self configureCell:recipeCell atIndexPath:indexPath];
return recipeCell;
}
- (void)configureCell:(RecipeTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// Configure the cell
Recipe *recipe = (Recipe *)[fetchedResultsController objectAtIndexPath:indexPath];
cell.recipe = recipe;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Recipe *recipe = (Recipe *)[fetchedResultsController objectAtIndexPath:indexPath];
[self showRecipe:recipe animated:YES];
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the managed object for the given index path
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
// Save the context.
NSError *error;
if (![context save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
#pragma mark -
#pragma mark Fetched results controller
- (NSFetchedResultsController *)fetchedResultsController {
// Set up the fetched results controller if needed.
if (fetchedResultsController == nil) {
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Recipe" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *typeDescriptor = [[NSSortDescriptor alloc] initWithKey:@"type" ascending:YES];
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:typeDescriptor, nameDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"type.name" cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[typeDescriptor release];
[nameDescriptor release];
[sortDescriptors release];
}
return fetchedResultsController;
}