CoreData: Apple's own template is not working??

Discussion in 'iOS Programming' started by Soulstorm, May 29, 2009.

  1. Soulstorm macrumors 68000

    Soulstorm

    Joined:
    Feb 1, 2005
    #1
    I made a project that uses core data from Apple's own template. It uses Core Data, so it requires iPhoneSDK 3.0. When I run the application, I can add elements to the table view just fine, but when I try to delete an element, I get this error:

    Code:
    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted).'
    Here is Apple's source for the tableViewController that is crashing:

    Code:
    //
    //  RootViewController.m
    //  iMeTest3
    //
    //  Created by Christos Sotiriou on 5/30/09.
    //  Copyright Tei of Pireus 2009. All rights reserved.
    //
    
    #import "RootViewController.h"
    
    
    @implementation RootViewController
    
    @synthesize fetchedResultsController, managedObjectContext;
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
    	// Set up the edit and add buttons.
        self.navigationItem.leftBarButtonItem = self.editButtonItem;
        
        UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject)];
        self.navigationItem.rightBarButtonItem = addButton;
        [addButton release];
    	
    	NSError *error;
    	if (![[self fetchedResultsController] performFetch:&error]) {
    		// Handle the error...
    	}
    }
    
    
    - (void)insertNewObject {
    	
    	// Create a new instance of the entity managed by the fetched results controller.
    	NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
    	NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];
    	NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
    	
    	// If appropriate, configure the new managed object.
    	[newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];
    	
    	// Save the context.
        NSError *error;
        if (![context save:&error]) {
    		// Handle the error...
    		NSLog(@"error!");
        }
    
        [self.tableView reloadData];
    }
    
    
    /*
    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
    }
    */
    /*
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
    }
    */
    /*
    - (void)viewWillDisappear:(BOOL)animated {
    	[super viewWillDisappear:animated];
    }
    */
    /*
    - (void)viewDidDisappear:(BOOL)animated {
    	[super viewDidDisappear:animated];
    }
    */
    
    /*
     // Override to allow orientations other than the default portrait orientation.
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    	// Return YES for supported orientations.
    	return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }
     */
    
    - (void)didReceiveMemoryWarning {
    	// Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];
    	
    	// Release any cached data, images, etc that aren't in use.
    }
    
    - (void)viewDidUnload {
    	// Release anything that can be recreated in viewDidLoad or on demand.
    	// e.g. self.myOutlet = nil;
    }
    
    
    #pragma mark Table view methods
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return [[fetchedResultsController sections] count];
    }
    
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    	id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
        return [sectionInfo numberOfObjects];
    }
    
    
    // Customize the appearance of table view cells.
    - (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];
        }
        
    	// Configure the cell.
    
    	NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
    
    	cell.textLabel.text = [[managedObject valueForKey:@"timeStamp"] description];
    	
        return cell;
    }
    
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        // Navigation logic may go here -- for example, create and push another view controller.
    	// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
        // NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
        // Pass the selected object to the new view controller.
        /// ...
    	// [self.navigationController pushViewController:anotherViewController animated:YES];
    	// [anotherViewController release];
    }
    
    
    /*
    // 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;
    }
    */
    
    
    // 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];
    		[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    		[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
    		// Save the context.
    		NSError *error;
    		if (![context save:&error]) {
    			// Handle the error...
    		}
    		[tableView reloadData];
    		
        }   
    }
    
    
    - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
        // The table view should not be re-orderable.
        return NO;
    }
    
    
    /*
    // NSFetchedResultsControllerDelegate method to notify the delegate that all section and object changes have been processed. 
    - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    	[self.tableView reloadData];
    }
    */
    
    
    - (NSFetchedResultsController *)fetchedResultsController {
        
        if (fetchedResultsController != nil) {
            return fetchedResultsController;
        }
        
        /*
    	 Set up the fetched results controller.
    	*/
    	// Create the fetch request for the entity.
    	NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    	// Edit the entity name as appropriate.
    	NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext];
    	[fetchRequest setEntity:entity];
    	
    	// Edit the sort key as appropriate.
    	NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:YES];
    	NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, 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:nil cacheName:@"Root"];
        aFetchedResultsController.delegate = self;
    	self.fetchedResultsController = aFetchedResultsController;
    	
    	[aFetchedResultsController release];
    	[fetchRequest release];
    	[sortDescriptor release];
    	[sortDescriptors release];
    	
    	return fetchedResultsController;
    }    
    
    
    - (void)dealloc {
    	[fetchedResultsController release];
    	[managedObjectContext release];
        [super dealloc];
    }
    
    
    @end
    
    
    It seems that this line causes problems:
    Code:
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    Any ideas?
     
  2. Amanjit Gill macrumors newbie

    Joined:
    Jul 22, 2009
    #2
    Hi, check out https://developer.apple.com/iphone/library/documentation/CoreData/Reference/NSFetchedResultsController_Class/Reference/Reference.html#/apple_ref/occ/cl/NSFetchedResultsController

    Look for this section:

    "Important: On iPhone OS 3.0, if you have a single section table view, there is an incompatibility between the values returned by NSFetchedResultsController and the values expected by UITableView. You can work around this incompatibility as follows:" (skipped)

    you basically have to override the two mentioned methods ...

    bye
    amanjit
     

Share This Page