核心数据插入错误

时间:2012-03-20 03:08:34

标签: iphone objective-c ios ios4 core-data

我与膳食和食物(即膳食<< ------>>食物)有很多关系。食物是一种抽象的类,可以是水果或蔬菜。我有一个RootViewController,它显示给定膳食中的所有食物。在一个课程中,我添加一个蔬菜,另一个我添加一个水果。

当我开始将这些添加到膳食时,我收到以下错误。我真的不确定发生了什么以及这是怎么回事。

Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableView.m:1046

CoreData: error: Serious application error.  An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.  Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)
2012-03-19 22:52:06.652 iGlucoTouch[682:11903] Meal Name: Meal #1    atIndex: 0

RootViewController.h

@interface RootViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate>
{            
    NSFetchedResultsController *_fetchedResultsController;
    NSManagedObjectContext *_context;    

    UITableView *_tableView;
}

@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSManagedObjectContext *context;
@property (nonatomic, retain) UITableView *tableView;

@end

RootViewController.m

@implementation RootViewController

@synthesize fetchedResultsController = _fetchedResultsController;
@synthesize context = _context;
@synthesize tableView = _tableView;


- (void)viewDidAppear:(BOOL)animated
{   
    self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320, 400) style:UITableViewStyleGrouped];

    self.tableView.dataSource = self;
    self.tableView.delegate = self;
    self.tableView.rowHeight = 60.0;

    [self.view addSubview:self.tableView];
    [self.tableView release];

    NSError *error;
    if (![self.fetchedResultsController performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);
    }
}

- (void)tableView:(UITableView *)tableView 
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle 
forRowAtIndexPath:(NSIndexPath *)indexPath 
{    
    self.context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 

    Food *food = [_fetchedResultsController objectAtIndexPath:indexPath];

    if (editingStyle == UITableViewCellEditingStyleDelete) {

        [self.meal removeFoodsObject:food];

        NSError *error;
        if (![self.context save:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            exit(-1);
        }
    }   
}


- (void)tableView:(UITableView *)tableView 
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle 
forRowAtIndexPath:(NSIndexPath *)indexPath 
{    
    self.context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 

    Food *food = [_fetchedResultsController objectAtIndexPath:indexPath];

    if (editingStyle == UITableViewCellEditingStyleDelete) {

        [self.meal removeFoodsObject:food];

        NSError *error;
        if (![self.context save:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            exit(-1);
        }
    }   
}

- (NSFetchedResultsController *)fetchedResultsController 
{       
    self.context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 

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

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Food" inManagedObjectContext:self.context];
    [fetchRequest setEntity:entity];

    NSPredicate *foodPredicate = [NSPredicate predicateWithFormat:@"ANY meals == %@", self.meal];
    [fetchRequest setPredicate:foodPredicate];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];    

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.context sectionNameKeyPath:nil cacheName:nil];

    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    [sort release];
    [fetchRequest release];
    [theFetchedResultsController release];

    return _fetchedResultsController;
}

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
{
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller 
   didChangeObject:(id)anObject 
       atIndexPath:(NSIndexPath *)indexPath 
     forChangeType:(NSFetchedResultsChangeType)type 
      newIndexPath:(NSIndexPath *)newIndexPath 
{        
    switch(type) {

        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller 
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo 
           atIndex:(NSUInteger)sectionIndex 
     forChangeType:(NSFetchedResultsChangeType)type 
{    
    switch(type) {

        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{
    [self.tableView endUpdates];
}

我在另一个类中添加了这样的水果或蔬菜:

self.context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];   

Fruit *fruit = [_fetchedResultsController objectAtIndexPath:indexPath];

[self.meal addFoodsObject:fruit];

NSError *error;
if (![self.context save:&error]) {
    NSLog(@"Error: %@", [error localizedDescription]);
}

2 个答案:

答案 0 :(得分:1)

显然我没有将fetchedResultsController和上下文设置为nil。我在dealloc中,但是没有被调用,因为这是在应用程序委托中声明的标签栏中的一个视图。所以我只是添加下面的代码。也许是因为我正在分享一个背景。

- (void)viewDidDisappear:(BOOL)animated
{
    self.fetchedResultsController = nil;
    self.context = nil;
}

答案 1 :(得分:0)

是的 - 听起来好像没有将新条目添加到NSArray的NSFetchResultsController支持的条目。在你[self.meal addFoodsObject:fruit]之后,你也应该能够打电话给

[self.tableView insertRowsAtIndexPaths: [NSArray arrayWithObject:newIndexPath]
                                  withRowAnimation: UITableViewRowAnimationRight];

自己。 Jeff LaMarche的链接是一个很好的解释。