【问题标题】:Animating Row Deletion in UITableView with CoreData gives Assertion failure使用 CoreData 在 UITableView 中动画行删除会导致断言失败
【发布时间】:2011-05-02 17:08:43
【问题描述】:

我有一个 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,但出现相同的错误。

【问题讨论】:

    标签: iphone cocoa-touch core-data uitableview


    【解决方案1】:
    - (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();
                }
            }
    
    
        }
    

    【讨论】:

    • 不,这行不通。我在发布之前确实尝试过。同样的错误:-[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1261.5/UITableView.m:92 中的断言失败
    【解决方案2】:

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

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


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

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

    无跟踪:委托设置为 零。控制器只是提供 访问数据,因为它是当 fetch 已执行。

    仅内存跟踪:委托是 非零并且设置了文件缓存名称 为零。控制器监控 结果集中的对象和更新 部分和订购信息 响应相关变化。

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

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

    【讨论】:

    • 我正在使用 NSFetchedResultsController 和一个没有问题的核心数据源。 sans-animation 代码成功删除了 coredata 对象。只是动画造成了麻烦。
    • @glenstorey 我想我第一次没有仔细阅读您的问题,请参阅我的编辑。
    【解决方案3】:

    1) 我设置了正确的委托。

    2) 我在 viewWillLoad 中删除了对 [self.tableview reloadData] 的调用;这(奇怪地)把一切都搞砸了(这篇文章给了我一个线索来寻找和删除什么:Serious Application Error in Core Data with fetchedResultsContainer)。

    【讨论】:

      【解决方案4】:

      当我们使用 NSFetchedResultsController 作为 UITableView 的 DataSource 时,我们不能在函数 tableView: commitEditingStyle: forRowAtIndexPath: 中调用deleteRowsAtIndexPaths: withRowAnimation: ,这将抛出异常,如问题所述。

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

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

      示例代码如下:

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

      【讨论】:

      • 这对我有用...很好地解决了令人沮丧的“深夜”之类的问题!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-30
      • 1970-01-01
      • 2019-11-02
      相关资源
      最近更新 更多