-1

我在我的 iPhone 应用程序中设置了父子核心数据关系。我有一个制造商对象和一个汽车对象。它是与制造商作为所有者的一对多关系。主视图是包含制造商的表视图。详细视图是另一个表视图,其中包含不同类型的汽车。我一直使用Tim Roadley 的核心数据教程作为基础。本教程使用斯坦福的核心数据表视图库作为表视图。

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

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

2012-07-29 23:39:33.561 应用程序 [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];

}

根据其他问题,我通过使用beginUpdatesand正确地做到了这一点endUpdates。这是一个令人费解的错误。谢谢你的帮助。

4

3 回答 3

1

我不确定您为什么要再次执行提取,如果从上下文中删除对象,则提取的结果控制器已经知道该更改。我认为您遇到的主要问题是在处理表的更新过程中调用 perform 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];
}

毕竟,只要行数与获取的对象数相匹配,就不会出现该错误。

于 2012-07-30T04:40:09.830 回答
0

尝试删除线条

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

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

于 2012-08-05T01:47:10.137 回答
0

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

于 2014-08-15T17:13:35.450 回答