使用 NSFetchedResultsController 时出现奇怪的删除行为

Posted

技术标签:

【中文标题】使用 NSFetchedResultsController 时出现奇怪的删除行为【英文标题】:Strange delete behaviour while using NSFetchedResultsController 【发布时间】:2014-01-01 15:40:41 【问题描述】:

我正在使用此代码删除我的NSFetchedResultsController 中的一行。除了删除符号之外,行删除的动画效果很好。该标志保持完全可见,直到该行褪色然后突然消失。但是一切都应该消失,包括删除符号,就像在其他应用程序中一样。我又错过了什么?

这里是所有相关的方法(所有方法都被正确调用,我尝试了不同的动画类型,但也没有用)。

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

    // Update the data model according to edit actions delete or insert.
    if (editingStyle == UITableViewCellEditingStyleDelete) 
        [self.managedObjectContext deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];

        //Adjust the indices of the remaining entries
        NSArray *fetchedResults = [[self.fetchedResultsController fetchedObjects] copy];

        int i = 1;
        for (MainCategory *fetchedResult in fetchedResults)
        
            fetchedResult.position = [NSNumber numberWithInt:i++];
        
    


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

    if(!self.reordering)
        if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext)
        
            switch(type)
            
                case NSFetchedResultsChangeInsert:
                    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                    break;

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

                case NSFetchedResultsChangeUpdate:
                    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    break;

                case NSFetchedResultsChangeMove:
                    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                    break;
            
        
    

好的,经过 10 次尝试后成功截屏 :-)

编辑:在这里您会看到问题:删除操作发生,要删除的行消失,而删除标志保持完全可见且不会消失。只有在行完全淡出后,删除标志才会立即消失。

编辑 2: 我已经缩小了范围。如果我用所有位置的新计算来评论这个循环,删除的效果和预期的一样好。但我需要更新这些职位,不是吗?或者你会怎么做?

【问题讨论】:

这种奇怪行为的屏幕截图可能很有用...... 你为什么要复制获取的对象?有什么原因吗? 我的表中有一个属性位置(此特定类别在当前表中的位置,根据用户选择的排序)。因此,如果一个类别被删除,所有其他职位都需要更新。尝试截屏 但是为什么要复制已获取的对象?我想没必要…… 但是for循环是必要的不是吗?所以我应该写 for(MainCategory *fetchedResult in [self.fetchedResultsController fetchedObjects])? 【参考方案1】:

我会尝试重新计算- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 方法中的位置。只是为了确保一切都完成了。否则我不知道在哪里做。也许有一个合适的通知来监听上下文的变化,但我不知道。

显然,

但我需要更新这些职位,不是吗?

这取决于您的需求。如果你不这样做,没有人会更新它们。但是如果您使用position 属性对商品进行排序,则需要为每个获取的元素重新计算。

所以,

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
    [self.tableView endUpdates];

    if(self.recalculatePosition)  // this means that somewhere you set that bool to YES

        // suspend the tracking of changes before???

        self.recalculatePosition = NO; 

        // for loop here...
    

【讨论】:

很遗憾没用。但我已经考虑过了。因为我只将这个位置用于排序,所以我认为保持它完全准确没有任何用处。当然,重新排序后我必须更新它。但不是删除后。如果缺少数字应该不是问题,因为排序仍然有效。【参考方案2】:

重新计算您的位置正在更新获取的对象,这会触发对您的表格的更多更新,这会干扰动画。

如果您需要 position 属性来支持手动排序,那么当您重新计算它时,您应该禁止通过 FRC 进行更新。看起来您已经有了一些允许这样做的状态,所以它应该相当简单。

【讨论】:

是的,试过了,但删除根本没有发生。我想我只是接受一些缺失的数字,这些数字将在重新排序后再次填充。因此,如果缺少某些内容并且我很高兴,则排序不会受到影响。 :-)

以上是关于使用 NSFetchedResultsController 时出现奇怪的删除行为的主要内容,如果未能解决你的问题,请参考以下文章

核心数据保存竞争条件错误

在 Swift 3 中难以配置 NSFetchedResultsController

为啥 beginUpdates/endUpdates 会重置表视图位置以及如何阻止它这样做?

测试使用

第一篇 用于测试使用

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?