使用CoreData在UITableView中动画行删除会导致断言失败

时间:2010-10-30 04:05:03

标签: iphone cocoa-touch core-data uitableview

我有一个UITableView,它显示了使用CoreData存储的对象列表。我可以使用以下代码删除对象:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
    NSLog(@"Delete row");
    [managedObjectContext deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];

    // Save the context.
    NSError *error;
    if (![managedObjectContext save:&error]) {
        /*do this gracefully one day */
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    [self refreshTables]; //where refreshTables just reloads the data the table is using and calls [self.tableView reloadData];
}

}

但它没有动画或美学。

当我尝试通过替换

进行动画制作时
[self refreshTables]; 

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

我收到以下错误:

  

断言失败 - [UITableView _endCellAnimationsWithContext:],> /SourceCache/UIKit_Sim/UIKit-1261.5/UITableView.m:920   2010-10-30 16:46:35.717 MyApp [38226:207] * 由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:第0节中的行数无效。更新(3)后现有部分中包含的行必须等于更新前该部分中包含的行数(3),加上或减去从该部分插入或删除的行数(0插入,1删除)。“

我已尝试在commitEditingStyle代码中的各个位置使用 deleteRowsAtIndexPaths 代码而没有运气(例如在从mOC中删除对象之前)但我似乎无法绕过这个错误。

我知道Apple的iPhoneCoreDataRecipes示例通过设置FetchedResultsController的委托处理编辑/删除行来处理问题,但是在开发的这个阶段,如果可能的话,我只想要一个简单的解决方案来动画那些删除的对象。

如何在从managedObjectContext中删除对象之前/之后动画删除行?

编辑:我在从mOC中删除项目之前和之后尝试使用deleteRowsAtIndexPaths,但出现了相同的错误。

4 个答案:

答案 0 :(得分:17)

当我们使用NSFetchedResultsController作为UITableView的DataSource时,我们无法在函数deleteRowsAtIndexPaths: withRowAnimation: 中调用tableView: commitEditingStyle: forRowAtIndexPath:,这将引发异常问题。

解决此问题的一种方法是从协议[self.tableView reloadData]中调用controllerDidChangeContent:中的NSFetchedResultsControllerDelegate。它实际上解决了,不再有删除淡入淡出动画。

因此,另一种方便的方法是在[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]中调用controller: didChangeObject: atIndexPath: forChangeType: newIndexPath:

示例代码如下:


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
   forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Delete NSManagedObject
    NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
    [context deleteObject:object];

    // Save
    NSError *error;
    if ([context save:&error] == NO) {
        // Handle Error.
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
      newIndexPath:(NSIndexPath *)newIndexPath
{
    if (type == NSFetchedResultsChangeDelete) {
        // Delete row from tableView.
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                              withRowAnimation:UITableViewRowAnimationFade];
    }
}

答案 1 :(得分:7)

1)我设置了一个正确的代表。

2)我在viewWillLoad中删除了一个调用[self.tableview reloadData];这是(奇怪的)弄乱了一切(这篇文章给了我一个线索,寻找和删除:Serious Application Error in Core Data with fetchedResultsContainer)。

答案 2 :(得分:0)

您是否正在使用NSFetchedResultsController?
您收到此错误,因为该对象仍在您的tableview数据源中。

也许at this stage in development您正在使用simple solution并使用来自NSFetchRequest的对象填充NSArrays。那么从托管对象上下文中删除对象

将毫无意义

您是否正在为NSFetchedResultsController使用缓存?我刚刚在文档中再看一下,发现了这个:

  

控制器因此有效地具有   确定了三种操作模式   是否有代表和   是否设置了缓存文件名。

     

无跟踪:委托设置为   零。控制器只是提供   访问数据时的情况   fetch已执行。

     

仅内存跟踪:代表是   非nil和文件缓存名称已设置   没有。控制器监控   结果集和更新中的对象   部分和订购信息   对相关变化的回应。

     

完全持久跟踪:代表   并且文件缓存名称是非零的。   控制器监视其中的对象   结果集和更新部分和   订购信息以响应   相关变化。控制器   维护一个持久的缓存   计算结果。

因此控制器的模式是“无跟踪”。这意味着如果从托管对象中删除对象,则不会从控制器中删除对象 just reloads the data代码中refreshTables的含义是什么?在删除行之前尝试执行相同的操作 或者添加使代表工作所需的20行。

答案 3 :(得分:-2)

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
 {
        if (editingStyle == UITableViewCellEditingStyleDelete) {
            NSLog(@"Delete row");

    // Delete the row first
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

    //Then delete the object.
            [managedObjectContext deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];

            // Save the context.
            NSError *error;
            if (![managedObjectContext save:&error]) {
                /*do this gracefully one day */
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }


    }