UITableView 行删除崩溃应用

Posted

技术标签:

【中文标题】UITableView 行删除崩溃应用【英文标题】:UITableView row delete crashes app 【发布时间】:2014-04-21 01:30:08 【问题描述】:

我有一个基于 Core Data 的表视图,它有一个简单的删除方法。这是可以在无数教程中找到的简单代码,但是,它会使应用程序崩溃并显示以下消息:

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 (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 (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

删除方法如下:

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



    if (editingStyle == UITableViewCellEditingStyleDelete) 

        // get garden to delete, delete it through Core Data


        Garden *gardenToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
        NSLog(@"Garden name: %@", gardenToDelete.gardenName);

        [self.managedObjectContext deleteObject:gardenToDelete];
        [self.managedObjectContext save:nil];

        [self.tableView beginUpdates];

        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];

        [self.tableView endUpdates];
        

我花了几个小时重新排列代码,删除 beginUpdateendUpdate 调用,检查其他解决方案。非常感谢您的帮助。

【问题讨论】:

什么是self.fetchedResultsController和self.managedObjectContext? 视图的核心数据栈对象 【参考方案1】:

您只需要从您的NSFetchedResultsController 中删除该对象,然后假设您已实现docs 中描述的委托方法,获取的结果控制器将更新表格视图。您不应该触摸表格视图行,NSFetchedResultsControllerDelegate 会完成所有这些操作。

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

  if (editingStyle == UITableViewCellEditingStyleDelete) 

      // deleting cell from fetched results contoller

      Garden *gardenToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
      NSLog(@"Garden name: %@", gardenToDelete.gardenName); 
      [self.managedObjectContext deleteObject:gardenToDelete];
      [self.managedObjectContext save:nil];
  

【讨论】:

试过了,该对象已从核心数据中删除,但该行保持不变。如果您点击该行,应用程序将崩溃(因为该行后面没有数据) @Andrew 查看我在回答中发布的文档链接,您需要在self.fetchedResultsController 上设置delegate,并实现更新的委托方法【参考方案2】:

您是否使用NSFetchedResultsController 的返回值实现- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section?保存后self.fetchedResultsController会刷新,但要确保tableView返回值的dataSource全部依赖self.fetchedResultsController

【讨论】:

【参考方案3】:

你是否实现了这些方法:

 - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath 
UITableView *tableView = self.tableView;

// my comment: mapIndexPathFromFetchResultsController function, I just use to get indexPath. You can remove it 
indexPath = [self mapIndexPathFromFetchResultsController:indexPath];
newIndexPath = [self mapIndexPathFromFetchResultsController:newIndexPath];

switch(type) 
    case NSFetchedResultsChangeInsert:
    
        [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
    

    case NSFetchedResultsChangeDelete:
    
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
    

    case NSFetchedResultsChangeUpdate:
    
        UITableViewCell *cell;
        cell = [tableView cellForRowAtIndexPath:indexPath];
        if (cell != nil)
        
            // my comment: just use the same with cellForRowAtIndexPath
            // - (void)syncViewConfigureCell:(UITableViewCell *)cell 
            // cell.textLabel.text = @""; etc. 
            [self syncViewConfigureCell:cell];
        
        break;
    

    case NSFetchedResultsChangeMove:
    
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [tableView insertRowsAtIndexPaths:@[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 
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
    

【讨论】:

mapIndexPathFromFetchResultsController: 方法是什么? syncViewConfigureCell: 方法是什么?

以上是关于UITableView 行删除崩溃应用的主要内容,如果未能解决你的问题,请参考以下文章

UITableView删除行到最后一条时崩溃

编辑模式下的 UITableView - 按 Delete 会使我的应用程序崩溃

尝试从UITableView中删除行时有时崩溃

NSFetchedResultsController 崩溃的 TableView 行删除?

由于自引用连接,从 UITableView 删除时应用程序崩溃

从 UItableview 删除一行时崩溃