核心数据表视图删除崩溃

时间:2012-07-30 03:47:25

标签: objective-c ios cocoa-touch uitableview core-data

我的iPhone应用程序中设置了父子Core Data关系。我有一个Manufacturer对象和一个Car对象。这是与制造商作为所有者的多对多关系。主视图是包含制造商的表视图。详细视图是另一个具有不同类型汽车的表格视图。我一直以Tim Roadley's Core Data Tutorial为基础。本教程使用Stanford's Core Data Table View Library作为表格视图。

添加汽车和制造商没有问题,但当我进入并在表格视图中删除多辆汽车时,我收到此错误:

 *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037

2012-07-29 23:39:33.561 App [16368:c07] * 由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:第0部分中的行数无效。更新(0)后现有部分中包含的行数必须等于更新前该部分中包含的行数(2),加上或减去从该部分插入或删除的行数(0)插入,1删除)并加上或减去移入或移出该部分的行数(0移入,0移出)。'

如果我删除了唯一的汽车,它会正常工作,直到我尝试添加新车,当我收到此错误时:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'manufacturer' between objects in different contexts (source = <Car: 0x6d96da0> (entity: Car; id: 0x6d8a3c0 <x-coredata:///Car/tC78E17EB-1D68-4998-8C4D-6D1199CE253F4> ; data: {
dateAdded = nil;
manufacturer = nil;
carName = new;
}) , destination = <Manufacturer: 0x6bb1f40> (entity: Manufacturer; id: 0x6d87340 <x-coredata://2E8DDF34-B01A-4203-A53E-73DBE6A2F976/Garden/p6> ; data: <fault>))'

这是我的编辑方法:

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

if (editingStyle == UITableViewCellEditingStyleDelete) {

    [self.tableView beginUpdates];

    Plant *plantToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
    NSLog(@"Deleting plant '%@'", plantToDelete.plantName);
    [self.managedObjectContext deleteObject:plantToDelete];
    [self.managedObjectContext save:nil];

    //delete empty tableview row
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
    NSLog(@"Before performFetch...");
    [self performFetch];
    NSLog(@"After performFetch...");

    [self.tableView endUpdates];
}
}

performFetch方法包含在前面提到的CoreDataTableViewController文件中。为方便起见,这里是:

(void)performFetch
{
_debug = YES;

if (self.fetchedResultsController) {
    if (self.fetchedResultsController.fetchRequest.predicate) {
        if (self.debug) NSLog(@"[%@ %@] fetching %@ with predicate: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName, self.fetchedResultsController.fetchRequest.predicate);
    } else {
        if (self.debug) NSLog(@"[%@ %@] fetching all %@ (i.e., no predicate)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName);
    }
    NSError *error;
    [self.fetchedResultsController performFetch:&error];
    if (error) NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]);
} else {
    if (self.debug) NSLog(@"[%@ %@] no NSFetchedResultsController (yet?)", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
[self.tableView reloadData];

}

根据其他问题,我使用beginUpdatesendUpdates正确执行此操作。这是一个令人费解的错误。谢谢你的帮助。

3 个答案:

答案 0 :(得分:1)

我不确定你为什么再次执行获取,如果从上下文中删除了一个对象,则获取的结果控制器已经知道该更改。我认为你遇到的主要问题是在处理表更新的过程中调用fetch。如果你注释掉那行,它是否还有错误?

此外,以下可能是也可能不是问题的另一部分,因为这是您与我自己的代码不同的地方:

我还没有在tableView:CommitEditingStyle:之前看过开始/结束编辑调用。我在该方法中的自己的进程通常删除对象而不关心表行。表行在fetchedResultController委托方法中进行协调,如下所示:

   -(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    //the fetch controller is about to start sending change notifications so prepare the tableview
    [self.tableView beginUpdates];
}


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

    // reconcile your rows here
    switch(type) {
     case NSFetchedResultsChangeInsert:

       break;

     case NSFetchedResultsChangeDelete:
       // this one is you
       [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
       break;

     case NSFetchedResultsChangeUpdate:

       break;

     case NSFetchedResultsChangeMove:

       break;
}

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];
}

只要行数与所有提取的对象的数量相匹配,就不会出现该错误。

答案 1 :(得分:0)

尝试删除行

//delete empty tableview row
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
NSLog(@"Before performFetch...");
[self performFetch];
NSLog(@"After performFetch...");

我相信CoreDataTableViewController会自动处理从表中删除行。您实际上是删除导致错误的行两次。

答案 2 :(得分:0)

当我打开一个作为Tim Roadley的CoreDataTableViewController的子类的tableViewController时,我遇到了同样的错误。我的特定应用程序不要求用户能够添加或删除行,但它允许他们按名称和距离重新排序获取的结果以及搜索数据。我使用了Dean David的答案(上面接受的答案),但在每个案例陈述之后我只添加了一个中断陈述。到目前为止,这个应用程序已经有用了!