使用添加功能时断言失败

时间:2011-07-19 09:02:33

标签: core-data uitableview nsfetchedresultscontroller

在一个表中,我有3个索引,每个索引都调用一个函数。在每个函数中,都有一个添加按钮,用于将数据添加到CoreData中。前两个工作,但当我按下第三个索引并按添加时,会出现此错误。

2011-07-19 16:57:11.079 CoreDataMelaka[2704:207] * **Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1447.6.4/UITableView.m:976**
2011-07-19 16:57:11.080 CoreDataMelaka[2704:207] **Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted). with userInfo (null)****

这是我称之为

的第三类代码
@implementation MainFoodsInfoController

@synthesize mainfoods;
@synthesize mainfoodsarray;
@synthesize fetchedResultsController;
@synthesize tableView;
@synthesize foodsbutton;
@synthesize editfoodsbutton;
@synthesize addfoodsbutton;


-(IBAction) foodslist:(id) sender 
{
    [self dismissModalViewControllerAnimated:YES];
}


-(IBAction) addmainfoods:(id)sender 
{
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
    AddMainFoodsController *addmainfoodsController=[[AddMainFoodsController alloc] initWithNibName:@"AddMainFoodsController" bundle:nil];
    addmainfoodsController.delegate=self;   
    addmainfoodsController.mainfoods =  [NSEntityDescription insertNewObjectForEntityForName:@"MainFoods" inManagedObjectContext:context];
    UINavigationController *navigatController=[[UINavigationController alloc] initWithRootViewController:addmainfoodsController];
    [self   presentModalViewController:navigatController animated:YES]; 
    [addmainfoodsController release];
    [navigatController release];
}


-(IBAction) editmainfoods:(id)sender 
{
    if([editfoodsbutton.title isEqualToString:@"Edit"]) 
    {
        editfoodsbutton.title=@"Done"; 
        [self.tableView setEditing:YES animated:YES];
    } 
    else 
    {
        editfoodsbutton.title=@"Edit"; 
        [self.tableView setEditing:NO animated:YES];
    }
}

-(void) addmainfoodsController:(AddMainFoodsController *)controller selectedsave:(BOOL) save 
{
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
    if(!save) {
        [context deleteObject:controller.mainfoods];
    } 
    NSError *error; if(![context save:&error])
    {
        NSLog(@"Unresolved error %@ %@", error, [error userInfo]); exit(-1);
    } 
    [self dismissModalViewControllerAnimated:YES];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{
    NSInteger count = [[self.fetchedResultsController sections] count];
    if (count == 0) 
    {
        count = 1;
    }
    return count;   
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    NSInteger numofRows = 0;
    if ([[self.fetchedResultsController sections] count] > 0) 
    {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
        numofRows = [sectionInfo numberOfObjects];
    }
    return numofRows;
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
    { 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
        cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
    }    

    // Configure the cell.
    NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = [[managedObject valueForKey:@"foodsname"] description];
    UIImage *pimage=[managedObject valueForKey:@"foodstableimage"]; 
    CGSize size=pimage.size; 
    CGFloat ratio = 0; if (size.width > size.height) 
    {
        ratio = 44.0 / size.width;
    } 
    else 
    {
        ratio = 44.0 / size.height;
    }
    CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size. height);
    UIGraphicsBeginImageContext(rect.size); 
    [pimage drawInRect:rect]; 
    cell.imageView.image=UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    EditMainFoodsController *editmainfoodsController = [[EditMainFoodsController alloc] initWithNibName:@"EditMainFoodsController" bundle:nil];
    MainFoods *selectedmainfoods = (MainFoods *) [fetchedResultsController objectAtIndexPath:indexPath];
    editmainfoodsController.mainfoods= selectedmainfoods;
    UINavigationController *naviggController=[[UINavigationController alloc] initWithRootViewController:editmainfoodsController];
    [self presentModalViewController:naviggController 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 = [self.fetchedResultsController managedObjectContext];
        [context deleteObject:[[self fetchedResultsController] objectAtIndexPath:indexPath]];
        NSError *error; if (![context save:&error]) 
        {
            // Handle the error...
        }
    }   
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[NSEntityDescription entityForName:@"MainFoods" inManagedObjectContext:context]];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"foodsname" ascending:YES];
    NSArray *sortDescriptors =[[NSArray alloc] initWithObjects:sortDescriptor,nil]; 
    [fetchRequest setSortDescriptors:sortDescriptors];
    self.tableView.rowHeight=44.0;
    NSError *error=nil;
    mainfoodsarray=(NSMutableArray *)[context executeFetchRequest:fetchRequest error:&error];   
    [sortDescriptor release];
    [sortDescriptors release];
    [fetchRequest release];
    [self.tableView reloadData];     
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title=@"Foods Info";
    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // Handle the error...
    }   


}

- (NSFetchedResultsController *)fetchedResultsController {
    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    CoreDataMelakaAppDelegate *appDelegate = (CoreDataMelakaAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[NSEntityDescription entityForName:@"MainFoods" inManagedObjectContext:context]];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"foodsname" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:@"Root"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;
    [aFetchedResultsController release];
    return fetchedResultsController;
}    

- (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;
    }
}

- (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 {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}


- (void)dealloc {
    [foodsbutton release];
    [editfoodsbutton release];
    [addfoodsbutton release];
    [tableView release];
    [super dealloc];
}

@end

这是导致崩溃的add类。当我按下add时,我想要调用这个类,但这会导致崩溃,其他2个类没有问题只有这个问题

@implementation AddMainFoodsController

@synthesize savebutton; 
@synthesize cancelbutton; 
@synthesize delegate; 
@synthesize foodsnewname; 
@synthesize foodsnewinfo; 
@synthesize foodsnewemailid;
@synthesize foodsnewcontactno;
@synthesize foodsimage1;
@synthesize foodsimage2;
@synthesize foodsimage3;
@synthesize foodstableimage;
@synthesize mainfoods;
@synthesize tempImage;

NSInteger countaddfoods = 0;

-(IBAction) cancel:(id) sender 
{
    [delegate addmainfoodsController: self selectedsave:NO];
}

-(IBAction) save:(id)sender
{ 
    mainfoods.foodsname = foodsnewname.text; 
    mainfoods.foodsemailid = foodsnewemailid.text; 
    mainfoods.foodscontactno = foodsnewcontactno.text;
    mainfoods.foodsinfo = foodsnewinfo.text;
    [delegate addmainfoodsController: self selectedsave:YES ];
}

-(IBAction) selectimagebutton1:(id)sender
{
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init] ;
    imagePicker.delegate = self;
    [self presentModalViewController:imagePicker animated:YES];
    [imagePicker release];
}

-(IBAction) selectimagebutton2:(id)sender
{
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init] ;
    imagePicker.delegate = self;
    [self presentModalViewController:imagePicker animated:YES];
    [imagePicker release];
}

-(IBAction) selectimagebutton3:(id)sender
{
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init] ;
    imagePicker.delegate = self;
    [self presentModalViewController:imagePicker animated:YES];
    [imagePicker release];
}

-(IBAction) selecttableimagebutton:(id)sender
{
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init] ;
    imagePicker.delegate = self;
    [self presentModalViewController:imagePicker animated:YES];
    [imagePicker release];
}


- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo
{
    tempImage = selectedImage;
    countaddfoods = countaddfoods + 1;

    [self setImage];
    [self dismissModalViewControllerAnimated:YES]; 
}

-(void) setImage
{
    if (countaddfoods == 1)
    {
        foodsimage1.image = tempImage;
        mainfoods.foodsimage1 = tempImage;
    }
    else if (countaddfoods == 2)
    {
        foodsimage2.image = tempImage;
        mainfoods.foodsimage2 = tempImage;
    }
    else if (countaddfoods == 3)
    {
        foodsimage3.image = tempImage;
        mainfoods.foodsimage3 = tempImage;
    }
    else 
    {
        foodstableimage.image = tempImage;
        mainfoods.foodstableimage = tempImage;
    }
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    [self dismissModalViewControllerAnimated:YES];
}

- (void)viewDidLoad 
{
    [super viewDidLoad]; self.title=@"New Foods"; 
    self.navigationItem.rightBarButtonItem = savebutton; 
    self.navigationItem.leftBarButtonItem = cancelbutton;
}

- (void)dealloc 
{ 
    [savebutton release]; 
    [cancelbutton release]; 
    [foodsnewname release]; 
    [foodsnewemailid release]; 
    [foodsnewcontactno release]; 
    [foodsnewinfo release];
    [foodsimage1 release];
    [foodsimage2 release];
    [foodsimage3 release];
    [foodstableimage release];
    [mainfoods release]; 
    [tempImage release];
    [super dealloc];
} 

@end

3 个答案:

答案 0 :(得分:8)

错误消息告诉您问题:

  

无效更新:第0部分中的行数无效   更新(0)后必须包含在现有部分中的行   等于之前该部分中包含的行数   update(0),加上或减去插入或删除的行数   该部分(1个插入,0个删除)。 userInfo(null) * *

在表格部分(0)中,您从零行开始,即空部分。然后你添加了1行,所以第(0)行计数应为1,但numberOfRowsInSection:返回零。

这个问题有三个可能的原因:

  1. 您没有在beginUpdate中使用controllerWillChangeContent:冻结tableview,因此tableview会在更新完成之前尝试重绘自己。
  2. 您的numberOfRowsInSection会返回该部分的错误行数。
  3. 您正在多次插入一个托管对象,或者您对插入/更新的验证失败。
  4. 没有代码,无法告诉你实际问题。

答案 1 :(得分:1)

return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];

至少它对我有用

答案 2 :(得分:0)

我遇到了同样的错误。我正在使用NSFetchedResultsControllerDelegate的委托。除了下面的代表之外,我评论代表的其余部分。

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {  
 self.tableView.reloadData()
 if self.fetchedResultsController.fetchedObjects?.count == 0 {
    } else {
  }
}

如果要使用所有委托,则需要正确管理行和部分。如果您没有正确管理行和部分,就会出现此错误。